Compare commits

...

4 Commits

Author SHA1 Message Date
ce9092d634 cart & checkout: UI enhacnements 2025-12-25 21:13:25 +03:00
90e729cdce implemt QRBottomSheet 2025-12-25 00:35:44 +03:00
f35cf0bd3a add qr bottom sheet 2025-12-25 00:35:32 +03:00
a98d1b7790 cart: fix description text height 2025-12-24 23:08:30 +03:00
30 changed files with 888 additions and 597 deletions

View File

@@ -166,6 +166,7 @@
"customizable": "قابل للتخصيص"
},
"cart": {
"leaveANoteHere": "أي تعليمات خاصة لطلبك..",
"title": "السلة",
"emptyCart": "سلة المشتريات فارغة",
"emptyCartMessage": "يبدو أنك لم تضيف أي عناصر إلى سلة المشتريات بعد. ابدأ في استكشاف قائمتنا للعثور على وجبات لذيذة!",
@@ -263,6 +264,8 @@
"checkRequiredFields": "يرجى التحقق من الحقول المطلوبة"
},
"checkout": {
"customerName": "اسم العميل",
"customerInformation": "تفاصيل العميل",
"title": "الدفع",
"cash": "كاش",
"creditDebitCard": "بطاقة ائتمان/ائتمان",
@@ -436,6 +439,12 @@
"howMuchWouldYouLikeToPay": "كم مبلغ تريد دفعه؟",
"confirm": "تأكيد",
"totalBill": "الفاتورة الكلية",
"remainingToPay": "المبلغ المتبقي"
"remainingToPay": "المبلغ المتبقي",
"scanQRCodeToPay": "مسح الكود الباري الى الدفع",
"copyQRCode": "نسخ الكود الباري",
"payWithQR": "دفع باستخدام الكود الباري",
"cancel": "إلغاء",
"done": "تم",
"inviteEveryonePayingWithYou": "دع الجميع يدفعوا معك"
}
}

View File

@@ -178,6 +178,7 @@
"customizable": "Customizable"
},
"cart": {
"leaveANoteHere": "Leave a note here..",
"title": "Cart",
"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!",
@@ -273,6 +274,8 @@
"checkRequiredFields": "Please check required fields"
},
"checkout": {
"customerName": "Customer Name",
"customerInformation": "Customer Information",
"title": "Checkout",
"cash": "Cash",
"creditDebitCard": "Credit/Debit Card",
@@ -448,6 +451,12 @@
"howMuchWouldYouLikeToPay": "How much would you like to pay?",
"confirm": "Confirm",
"totalBill": "Total Bill",
"remainingToPay": "Remaining to Pay"
"remainingToPay": "Remaining to Pay",
"scanQRCodeToPay": "Scan QR Code to Pay",
"copyQRCode": "Copy QR Code",
"payWithQR": "Pay with QR",
"cancel": "Cancel",
"done": "Done",
"inviteEveryonePayingWithYou": "Invite everyone paying with you"
}
}

View File

@@ -104,7 +104,7 @@ export default function CartActionsButtons({ item }: { item: CartItem }) {
)}
<InputNumber
min={1}
max={100}
max={99}
value={item.quantity || 1}
onChange={(value: number | null) =>
dispatch(

View File

@@ -42,7 +42,7 @@ export function TipBottomSheet({
showCloseButton={false}
initialSnap={1}
height={370}
snapPoints={["30vh"]}
snapPoints={[370]}
>
<div
style={{
@@ -52,7 +52,9 @@ export function TipBottomSheet({
justifyContent: "center",
}}
>
<WaiterRewardingIcon />
<div style={{ marginTop: 20 }}>
<WaiterRewardingIcon />
</div>
<br />

View File

@@ -1,22 +1,26 @@
interface DeleteIconType {
className?: string;
onClick?: () => void;
color?: string;
dimension?: number;
}
const DeleteIcon = ({ className, onClick }: DeleteIconType) => {
const DeleteIcon = ({ className, onClick, color, dimension }: DeleteIconType) => {
return (
<svg
width="12"
height="12"
viewBox="0 0 12 12"
width={dimension || "14"}
height={dimension || "14"}
viewBox="0 0 14 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
onClick={onClick}
>
<path
d="M3 2.4V0.6C3 0.44087 3.06321 0.288258 3.17574 0.175736C3.28826 0.0632141 3.44087 0 3.6 0H8.4C8.55913 0 8.71174 0.0632141 8.82426 0.175736C8.93679 0.288258 9 0.44087 9 0.6V2.4H12V3.6H10.8V11.4C10.8 11.5591 10.7368 11.7117 10.6243 11.8243C10.5117 11.9368 10.3591 12 10.2 12H1.8C1.64087 12 1.48826 11.9368 1.37574 11.8243C1.26321 11.7117 1.2 11.5591 1.2 11.4V3.6H0V2.4H3ZM6.8484 7.2L7.9092 6.1392L7.0608 5.2908L6 6.3516L4.9392 5.2908L4.0908 6.1392L5.1516 7.2L4.0908 8.2608L4.9392 9.1092L6 8.0484L7.0608 9.1092L7.9092 8.2608L6.8484 7.2ZM4.2 1.2V2.4H7.8V1.2H4.2Z"
fill="#DC2626"
d="M11.375 3.20866L11.0133 9.05658C10.9212 10.5505 10.8751 11.2977 10.5 11.835C10.3148 12.1005 10.0764 12.3246 9.8 12.493C9.24175 12.8337 8.49333 12.8337 6.9965 12.8337C5.49733 12.8337 4.74775 12.8337 4.18833 12.4924C3.91177 12.3237 3.67337 12.0992 3.48833 11.8332C3.11383 11.2954 3.06833 10.547 2.9785 9.05074L2.625 3.20866M1.75 3.20866H12.25M9.366 3.20866L8.96758 2.38733C8.70333 1.84133 8.57092 1.56891 8.34283 1.39858C8.29217 1.36084 8.23852 1.32729 8.18242 1.29824C7.92983 1.16699 7.6265 1.16699 7.02042 1.16699C6.39858 1.16699 6.08767 1.16699 5.83042 1.30349C5.77355 1.33395 5.71931 1.36907 5.66825 1.40849C5.43783 1.58524 5.30892 1.86816 5.05108 2.43341L4.69758 3.20866M5.54167 9.62533V6.12533M8.45833 9.62533V6.12533"
stroke={color || "#DD4143"}
strokeWidth="1.5"
strokeLinecap="round"
/>
</svg>
);

View File

@@ -1,13 +1,14 @@
interface PlusIconType {
className?: string;
onClick?: () => void;
dimesion?: string
}
const PlusIcon = ({ className, onClick }: PlusIconType) => {
const PlusIcon = ({ className, onClick, dimesion }: PlusIconType) => {
return (
<svg
width="16"
height="16"
width={dimesion || "16"}
height={dimesion || "16"}
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"

View File

@@ -0,0 +1,55 @@
interface QRIconType {
className?: string;
onClick?: () => void;
}
const QRIcon = ({ className, onClick }: QRIconType) => {
return (
<svg
width="116"
height="116"
viewBox="0 0 116 116"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
onClick={onClick}
>
<path
d="M4.8335 4.8335H53.1668V53.1668H4.8335V4.8335ZM14.5002 14.5002V43.5002H43.5002V14.5002H14.5002Z"
fill="black"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M24.1665 24.1665H33.8332V33.8332H24.1665V24.1665Z"
fill="black"
/>
<path
d="M62.8335 4.8335H111.167V53.1668H62.8335V4.8335ZM72.5002 14.5002V43.5002H101.5V14.5002H72.5002Z"
fill="black"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M82.1665 24.1665H91.8332V33.8332H82.1665V24.1665Z"
fill="black"
/>
<path
d="M4.8335 62.8335H53.1668V111.167H4.8335V62.8335ZM14.5002 72.5002V101.5H43.5002V72.5002H14.5002Z"
fill="black"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M24.1665 82.1665H33.8332V91.8332H24.1665V82.1665Z"
fill="black"
/>
<path
d="M111.167 91.8335H91.8335V111.167H62.8335V62.8335V91.8335H72.5002V101.5H82.1668V72.5002H72.5002V62.8335H67.6668H82.1668V72.5002H91.8335V82.1668H101.5V62.8335H111.167V91.8335ZM111.167 101.5V111.167H101.5V101.5H111.167Z"
fill="black"
/>
</svg>
);
};
export default QRIcon;

View File

@@ -32,7 +32,7 @@ export default function InputCard({
placeholder={placeholder}
size="large"
autoFocus={false}
style={{ padding: "7px 11px", height: 50, borderRadius: 888 }}
style={{ padding: "7px 11px", height: 48, borderRadius: 888 }}
value={value}
onChange={handleChange}
/>

View File

@@ -88,7 +88,7 @@ const PaymentMethods = () => {
}}
size="large"
>
<Space orientation="vertical" style={{ width: "100%" }}>
<Space orientation="vertical" style={{ width: "100%", gap: 16 }}>
{options.map((option) => (
<div key={option.value}>
<Radio
@@ -96,7 +96,7 @@ const PaymentMethods = () => {
value={option.value}
onClick={() => onPaymentSelect(option.value)}
style={{
height: 50,
height: 48,
borderRadius: 888,
border: "1px solid #DDD",
padding: 16,

View File

@@ -86,7 +86,7 @@ export const PhoneInputWrapper = ({
const inputStyle = useMemo(
() => ({
borderRadius: 1000,
height: 50,
height: 48,
width: "100%",
color: themeName === "light" ? "#000" : "#FFF",
backgroundColor: themeName === "light" ? "#FFF" : ProBlack1,

View File

@@ -37,9 +37,15 @@ const ProRatioGroups = ({
onChange={handleChange}
{...props}
>
<Space direction="vertical" style={{ width: "100%" }}>
<Space orientation="vertical" style={{ width: "100%" }}>
{options.map((option) => (
<Radio key={option.value} value={option.value}>
<Radio
key={option.value}
value={option.value}
// style={{
// height: 48,
// }}
>
<div
style={{
display: "flex",

View File

@@ -70,6 +70,7 @@ interface CartState {
pickupType: string;
order: any;
splitBillAmount: number;
customerName: string;
}
// localStorage keys
@@ -187,6 +188,7 @@ const initialState: CartState = {
pickupType: getFromLocalStorage(CART_STORAGE_KEYS.PICKUP_TYPE, ""),
order: getFromLocalStorage(CART_STORAGE_KEYS.ORDER, null),
splitBillAmount: 0,
customerName: "",
};
const orderSlice = createSlice({
@@ -637,6 +639,9 @@ const orderSlice = createSlice({
updateSplitBillAmount(state, action: PayloadAction<number>) {
state.splitBillAmount = action.payload;
},
updateCustomerName(state, action: PayloadAction<string>) {
state.customerName = action.payload;
},
},
});
@@ -675,6 +680,7 @@ export const {
updatePickUpType,
updateOrder,
updateSplitBillAmount,
updateCustomerName,
} = orderSlice.actions;
// Tax calculation helper functions

View File

@@ -605,3 +605,8 @@
outline: 2px solid #ffffff;
outline-offset: 2px;
}
.deleteIcon {
position: relative;
top: 1px;
}

View File

@@ -24,7 +24,7 @@ export default function CarPlateCard() {
placeholder={t("cart.plateNumber")}
size="large"
autoFocus={false}
style={{ padding: "7px 11px", height: 50, borderRadius: 888 }}
style={{ padding: "7px 11px", height: 48, borderRadius: 888 }}
value={plateCar}
onChange={(e) => {
dispatch(updatePlateCar(e.target.value));

View File

@@ -1,5 +1,4 @@
import { PlusOutlined } from "@ant-design/icons";
import { Card, Divider, Space, Layout } from "antd";
import { Card, Divider, Space, Layout, Button } from "antd";
import ArabicPrice from "components/ArabicPrice";
import CartActionsButtons from "components/CartActionsButtons/CartActionsButtons.tsx";
import ImageWithFallback from "components/ImageWithFallback";
@@ -9,8 +8,7 @@ import ProTitle from "components/ProTitle.tsx";
import { selectCart } from "features/order/orderSlice.ts";
import styles from "pages/cart/cart.module.css";
import YouMightAlsoLike from "pages/cart/components/youMayLike/YouMightAlsoLike.tsx";
import { Link, useParams } from "react-router-dom";
import { colors } from "ThemeConstants.ts";
import { Link, useNavigate, useParams } from "react-router-dom";
import { useAppSelector } from "redux/hooks.ts";
@@ -18,13 +16,14 @@ import { FormInstance } from "antd";
import useBreakPoint from "hooks/useBreakPoint.ts";
import CarPlateCard from "pages/cart/components/CarPlateCard.tsx";
import CartFooter from "pages/cart/components/cartFooter/CartFooter.tsx";
import CouponCard from "pages/cart/components/CouponCard.tsx";
import SpecialRequestCard from "pages/cart/components/specialRequest/SpecialRequestCard.tsx";
import TableNumberCard from "pages/cart/components/TableNumberCard.tsx";
import TimeEstimateCard from "pages/cart/components/timeEstimate/TimeEstimateCard.tsx";
import { OrderType } from "pages/checkout/hooks/types";
import { useTranslation } from "react-i18next";
import { Variant } from "utils/types/appTypes";
import DeleteIcon from "components/Icons/DeleteIcon";
import PlusIcon from "components/Icons/PlusIcon";
interface CartMobileTabletLayoutProps {
form: FormInstance;
@@ -39,8 +38,8 @@ export default function CartMobileTabletLayout({
const { subdomain } = useParams();
const { pickup_type } = useAppSelector((state) => state.order.restaurant);
const { isMobile, isTablet } = useBreakPoint();
const getResponsiveClass = () => (isTablet ? "tablet" : "mobile");
const navigate = useNavigate();
const getMenuItemImageStyle = () => {
if (isMobile) {
@@ -82,11 +81,21 @@ export default function CartMobileTabletLayout({
>
<div
style={{
marginTop: 10,
marginTop: 3,
boxSizing: "border-box", // Explicit box model definition
}}
>
<ProTitle level={5} style={{ whiteSpace: "nowrap" }}>
<ProTitle
level={5}
style={{
whiteSpace: "nowrap",
fontWeight: 500,
fontStyle: "Medium",
fontSize: 18,
lineHeight: "140%",
letterSpacing: 0,
}}
>
{t("cart.yourOrder")}
</ProTitle>
</div>
@@ -100,25 +109,29 @@ export default function CartMobileTabletLayout({
textAlign: "end",
}}
>
<div
<Button
shape="circle"
iconPlacement="start"
icon={
<DeleteIcon
className={styles.deleteIcon}
color={"#C0BFC4"}
dimension={16}
/>
}
size="small"
className={styles.addButton}
style={{
color: colors.primary,
width: 32,
height: 32,
border: "1px solid #DEDEE0",
}}
>
<PlusOutlined
style={{
color: colors.primary,
marginLeft: 5,
marginTop: 15,
}}
/>
{t("cart.addMore")}
</div>
/>
</Link>
</div>
{items.length >= 1 && (
<Divider style={{ margin: "0px 0px 10px 0px" }} />
<Divider style={{ margin: "8px 0px 12px 0px" }} />
)}
{items.map((item, index) => (
<div key={index} style={{ position: "relative" }}>
@@ -178,10 +191,10 @@ export default function CartMobileTabletLayout({
overflowWrap: "break-word",
lineHeight: "1.4",
maxHeight: isMobile
? "2.8em"
? "3em"
: isTablet
? "4.8em"
: "6.8em",
? "5em"
: "7em",
fontWeight: 500,
letterSpacing: "0.01em",
width: "55%",
@@ -230,6 +243,16 @@ export default function CartMobileTabletLayout({
)}
</div>
))}
<Button
style={{ width: "100%", marginTop: 24, color: "#4C4A58" }}
onClick={() => {
navigate(`/${subdomain}/menu?${
orderType ? `orderType=${orderType}` : ""
}`);
}}
>
<PlusIcon dimesion="18" /> {t("cart.addMore")}
</Button>
</Card>
</div>
</div>

View File

@@ -83,7 +83,7 @@ export default function CouponCard() {
placeholder={t("cart.couponCode")}
size="large"
autoFocus={false}
style={{ padding: "7px 11px", height: 50 }}
style={{ padding: "7px 11px", height: 48 }}
onChange={(e) => {
dispatch(updateCoupon(e.target.value));
}}

View File

@@ -1,5 +1,12 @@
.inputField {
height: 50px;
border-radius: 8px !important;
justify-content: space-between;
padding-top: 12px;
padding-right: 16px;
padding-bottom: 12px;
padding-left: 16px;
opacity: 1;
border-width: 1px;
}
.editButton {

View File

@@ -9,13 +9,13 @@ import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useAppDispatch, useAppSelector } from "redux/hooks.ts";
import styles from "./SpecialRequestCard.module.css";
import TextArea from "antd/es/input/TextArea";
export default function SpecialRequestCard() {
const { t } = useTranslation();
const { isDesktop } = useBreakPoint();
const dispatch = useAppDispatch();
const { specialRequest } = useAppSelector(selectCart);
const { isRTL } = useAppSelector((state) => state.locale);
const [isSpecialRequestOpen, setIsSpecialRequestOpen] = useState(false);
const handleSpecialRequestSave = (value: string) => {
@@ -32,12 +32,8 @@ export default function SpecialRequestCard() {
title={t("cart.specialRequest")}
dividerStyle={{ margin: "5px 0 0 0" }}
>
<Form.Item
label={t("cart.specialRequest")}
name="specialRequest"
style={{ position: "relative", top: -5 }}
>
<Input
<Form.Item name="specialRequest" style={{ marginTop: 12 }}>
{/* <Input
placeholder={t("cart.specialRequest")}
size="large"
autoFocus={false}
@@ -51,6 +47,13 @@ export default function SpecialRequestCard() {
<u>{t("cart.editNote")}</u> {isRTL ? <LeftOutlined /> : <RightOutlined />}
</div>
}
/> */}
<TextArea
placeholder={t("cart.leaveANoteHere")}
rows={2}
autoFocus={false}
className={styles.inputField}
onChange={(e) => handleSpecialRequestSave(e.target.value)}
/>
</Form.Item>
</ProInputCard>

View File

@@ -22,8 +22,8 @@ export function BottomSheet({
title={t("cart.selectTimeEstimate")}
showCloseButton={true}
initialSnap={1}
height={555}
snapPoints={["65vh"]}
height={495}
snapPoints={[495]}
>
<Content onSave={onSave} onClose={onClose} />
</ProBottomSheet>

View File

@@ -0,0 +1,3 @@
.customerInformationCard {
height: 215px !important;
}

View File

@@ -0,0 +1,44 @@
import ProInputCard from "components/ProInputCard/ProInputCard.tsx";
import ProPhoneInput from "components/ProPhoneInput";
import { selectCart, updateCustomerName } from "features/order/orderSlice";
import { OrderType } from "pages/checkout/hooks/types.ts";
import { useTranslation } from "react-i18next";
import { useAppDispatch, useAppSelector } from "redux/hooks";
import { Form, Input } from "antd";
import styles from "./CustomerInformationCard.module.css";
export default function CustomerInformationCard() {
const { t } = useTranslation();
const { orderType } = useAppSelector(selectCart);
const dispatch = useAppDispatch();
const customerName = useAppSelector((state) => state.order.customerName);
return (
orderType !== OrderType.Gift && (
<>
<ProInputCard
title={t("checkout.customerInformation")}
className={styles.customerInformationCard}
>
<div style={{ position: "relative", top: -25 }}>
<Form.Item label={t("checkout.customerName")} name="customerName">
<Input
placeholder={t("checkout.customerName")}
size="large"
autoFocus={false}
style={{ padding: "7px 11px", height: 48, borderRadius: 888 }}
value={customerName}
onChange={(e) => {
dispatch(updateCustomerName(e.target.value));
}}
/>
</Form.Item>
</div>
<div style={{ position: "relative", top: -30 }}>
<ProPhoneInput label={t("login.phone")} propName="phone" />
</div>
</ProInputCard>
</>
)
);
}

View File

@@ -1,3 +0,0 @@
.phoneCard {
height: 150px !important;
}

View File

@@ -1,27 +0,0 @@
import ProInputCard from "components/ProInputCard/ProInputCard.tsx";
import ProPhoneInput from "components/ProPhoneInput";
import { selectCart } from "features/order/orderSlice";
import { OrderType } from "pages/checkout/hooks/types.ts";
import { useTranslation } from "react-i18next";
import { useAppSelector } from "redux/hooks";
import styles from "./PhoneCard.module.css";
export default function PhoneCard() {
const { t } = useTranslation();
const { orderType } = useAppSelector(selectCart);
return (
orderType !== OrderType.Gift && (
<>
<ProInputCard
title={t("checkout.phoneNumber")}
className={styles.phoneCard}
>
<div style={{ position: "relative", top: -20 }}>
<ProPhoneInput label={t("login.phone")} propName="phone" />
</div>
</ProInputCard>
</>
)
);
}

View File

@@ -15,8 +15,8 @@ import RewardWaiterCard from "pages/cart/components/RewardWaiterCard";
import ProInputCard from "components/ProInputCard/ProInputCard";
import ProRatioGroups from "components/ProRatioGroups/ProRatioGroups";
import CouponCard from "pages/cart/components/CouponCard";
import PhoneCard from "./components/PhoneCard";
import BriefMenuCard from "./components/BriefMenuCard";
import CustomerInformationCard from "./components/CustomerInformationCard";
export default function CheckoutPage() {
const { t } = useTranslation();
@@ -37,7 +37,7 @@ export default function CheckoutPage() {
<ProHeader>{t("checkout.title")}</ProHeader>
<Layout.Content className={styles.checkoutContainer}>
<PaymentMethods />
{!token && <PhoneCard />}
{!token && <CustomerInformationCard />}
<AddressSummary />
{orderType === OrderType.ToRoom && (
<InputCard

View File

@@ -99,19 +99,25 @@ export default function PayButton({ form }: { form: FormInstance }) {
<CustomAmountChoiceBottomSheet
isOpen={isCustomAmountOpen}
onClose={() => setIsCustomAmountOpen(false)}
onClose={() => {
setIsCustomAmountOpen(false);
}}
onRemoveSplitWay={handleRemoveSplitWay}
/>
<EqualltyChoiceBottomSheet
isOpen={isEqualityOpen}
onClose={() => setIsEqualityOpen(false)}
onClose={() => {
setIsEqualityOpen(false);
}}
onRemoveSplitWay={handleRemoveSplitWay}
/>
<PayForYourItemsChoiceBottomSheet
isOpen={isPayForItemsOpen}
onClose={() => setIsPayForItemsOpen(false)}
onClose={() => {
setIsPayForItemsOpen(false);
}}
onRemoveSplitWay={handleRemoveSplitWay}
/>
</>

View File

@@ -12,11 +12,11 @@ import { useAppDispatch, useAppSelector } from "redux/hooks";
import ProText from "components/ProText";
import ArabicPrice from "components/ArabicPrice";
import styles from "./SplitBill.module.css";
import { QRBottomSheet } from "./QRBottomSheet";
interface SplitBillChoiceBottomSheetProps {
isOpen: boolean;
onClose: () => void;
onSave?: (value: string) => void;
onRemoveSplitWay?: () => void;
}
@@ -32,7 +32,7 @@ export function CustomAmountChoiceBottomSheet({
const [amount, setAmount] = useState<string>(
splitBillAmount > 0 ? splitBillAmount.toString() : "",
);
const [isQROpen, setIsQROpen] = useState(false);
useEffect(() => {
if (isOpen && splitBillAmount > 0) {
setAmount(splitBillAmount.toString());
@@ -42,6 +42,7 @@ export function CustomAmountChoiceBottomSheet({
const handleSave = () => {
const numAmount = parseFloat(amount) || 0;
dispatch(updateSplitBillAmount(numAmount));
setIsQROpen(true);
onClose();
};
@@ -61,135 +62,138 @@ export function CustomAmountChoiceBottomSheet({
const previewRemaining = originalTotalBill - currentAmount;
return (
<ProBottomSheet
isOpen={isOpen}
onClose={onClose}
title={t("splitBill.payAsCustomAmount")}
showCloseButton={true}
initialSnap={1}
height={430}
snapPoints={[430]}
contentStyle={{
padding: 0,
}}
>
<div
style={{
padding: "20px",
display: "flex",
flexDirection: "column",
gap: 20,
<>
<ProBottomSheet
isOpen={isOpen}
onClose={onClose}
title={t("splitBill.payAsCustomAmount")}
showCloseButton={true}
initialSnap={1}
height={430}
snapPoints={[430]}
contentStyle={{
padding: 0,
}}
>
<div>
<ProText
style={{
fontWeight: 400,
fontStyle: "Regular",
fontSize: 16,
lineHeight: "140%",
letterSpacing: "0%",
}}
>
{t("splitBill.howMuchWouldYouLikeToPay")}
</ProText>
<Form.Item
label={t("splitBill.amount")}
name="amount"
style={{ position: "relative", top: -5 }}
>
<InputNumber
value={amount}
onChange={(value) => {
setAmount(value?.toString() || "");
dispatch(updateSplitBillAmount(Number(value) || 0));
<div
style={{
padding: "20px",
display: "flex",
flexDirection: "column",
gap: 20,
}}
>
<div>
<ProText
style={{
fontWeight: 400,
fontStyle: "Regular",
fontSize: 16,
lineHeight: "140%",
letterSpacing: "0%",
}}
placeholder={t("splitBill.amount")}
max={(grandTotal + splitBillAmount).toString()}
min={"0"}
style={{ width: "100%", fontSize: "1rem" }}
/>
</Form.Item>
>
{t("splitBill.howMuchWouldYouLikeToPay")}
</ProText>
<Form.Item
label={t("splitBill.amount")}
name="amount"
style={{ position: "relative", top: -5 }}
>
<InputNumber
value={amount}
onChange={(value) => {
setAmount(value?.toString() || "");
dispatch(updateSplitBillAmount(Number(value) || 0));
}}
placeholder={t("splitBill.amount")}
max={(grandTotal + splitBillAmount).toString()}
min={"0"}
style={{ width: "100%", fontSize: "1rem" }}
/>
</Form.Item>
</div>
</div>
</div>
<div
style={{
display: "flex",
flexDirection: "column",
backgroundColor: "var(--background)",
padding: "20px",
opacity: 1,
gap: 8,
borderTopLeftRadius: 24,
borderTopRightRadius: 24,
paddingTop: 12,
paddingRight: 24,
paddingBottom: 24,
paddingLeft: 24,
}}
>
<div className={styles.summaryRow}>
<ProText
style={{
fontWeight: 400,
fontStyle: "Regular",
fontSize: 14,
lineHeight: "140%",
letterSpacing: "0%",
}}
>
{t("splitBill.totalBill")}
</ProText>
<ArabicPrice price={previewTotalBill} />
<div
style={{
display: "flex",
flexDirection: "column",
backgroundColor: "var(--background)",
padding: "20px",
opacity: 1,
gap: 8,
borderTopLeftRadius: 24,
borderTopRightRadius: 24,
paddingTop: 12,
paddingRight: 24,
paddingBottom: 24,
paddingLeft: 24,
}}
>
<div className={styles.summaryRow}>
<ProText
style={{
fontWeight: 400,
fontStyle: "Regular",
fontSize: 14,
lineHeight: "140%",
letterSpacing: "0%",
}}
>
{t("splitBill.totalBill")}
</ProText>
<ArabicPrice price={previewTotalBill} />
</div>
<div className={styles.summaryRow}>
<ProText
style={{
fontWeight: 400,
fontStyle: "Regular",
fontSize: 14,
lineHeight: "140%",
letterSpacing: "0%",
}}
>
{t("splitBill.remainingToPay")}
</ProText>
<ArabicPrice price={Math.max(0, previewRemaining)} />
</div>
</div>
<div className={styles.summaryRow}>
<ProText
style={{
fontWeight: 400,
fontStyle: "Regular",
fontSize: 14,
lineHeight: "140%",
letterSpacing: "0%",
}}
>
{t("splitBill.remainingToPay")}
</ProText>
<ArabicPrice price={Math.max(0, previewRemaining)} />
</div>
</div>
<div
style={{
display: "flex",
gap: 12,
margin: 20,
}}
>
<Button
<div
style={{
flex: 1,
backgroundColor: "#FEEDED",
color: "#DD4143",
boxShadow: "none",
border: "none",
display: "flex",
gap: 12,
margin: 20,
}}
onClick={handleRemoveSplitWay}
>
{t("splitBill.removeSplit")}
</Button>
<Button
type="primary"
style={{
flex: 1,
boxShadow: "none",
}}
onClick={handleSave}
disabled={!amount || parseFloat(amount) <= 0}
>
{t("splitBill.confirm")}
</Button>
</div>
</ProBottomSheet>
<Button
style={{
flex: 1,
backgroundColor: "#FEEDED",
color: "#DD4143",
boxShadow: "none",
border: "none",
}}
onClick={handleRemoveSplitWay}
>
{t("splitBill.removeSplit")}
</Button>
<Button
type="primary"
style={{
flex: 1,
boxShadow: "none",
}}
onClick={handleSave}
disabled={!amount || parseFloat(amount) <= 0}
>
{t("splitBill.confirm")}
</Button>
</div>
</ProBottomSheet>
<QRBottomSheet isOpen={isQROpen} onClose={() => setIsQROpen(false)} />
</>
);
}

View File

@@ -1,6 +1,6 @@
import { Button } from "antd";
import { ProBottomSheet } from "components/ProBottomSheet/ProBottomSheet.tsx";
import { useMemo } from "react";
import { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import ProText from "components/ProText";
@@ -15,6 +15,7 @@ import { ProGray1 } from "ThemeConstants";
import PayForActions from "../../../split-bill/components/PayForActions";
import TotalPeopleActions from "../../../split-bill/components/TotalPeopleActions";
import styles from "./SplitBill.module.css";
import { QRBottomSheet } from "./QRBottomSheet";
interface SplitBillChoiceBottomSheetProps {
isOpen: boolean;
@@ -37,7 +38,7 @@ export function EqualltyChoiceBottomSheet({
const dispatch = useAppDispatch();
const { tmp, splitBillAmount } = useAppSelector(selectCart);
const grandTotal = useAppSelector(selectGrandTotal);
const [isQROpen, setIsQROpen] = useState(false);
const splitBillTmp = tmp as SplitBillTmp;
const totalPeople = splitBillTmp?.totalPeople || 2;
const payFor = splitBillTmp?.payFor || 1;
@@ -55,6 +56,7 @@ export function EqualltyChoiceBottomSheet({
const handleSave = () => {
dispatch(updateSplitBillAmount(splitAmount));
setIsQROpen(true);
onClose();
};
@@ -65,281 +67,284 @@ export function EqualltyChoiceBottomSheet({
};
return (
<ProBottomSheet
isOpen={isOpen}
onClose={onClose}
title={t("splitBill.divideTheBillEqually")}
showCloseButton={true}
initialSnap={1}
height={630}
snapPoints={[630]}
contentStyle={{
padding: 0,
}}
>
<div
style={{
display: "flex",
flexDirection: "column",
marginTop: 20,
<>
<ProBottomSheet
isOpen={isOpen}
onClose={onClose}
title={t("splitBill.divideTheBillEqually")}
showCloseButton={true}
initialSnap={1}
height={630}
snapPoints={[630]}
contentStyle={{
padding: 0,
}}
>
{/* Spinner Visualization - Blank Spin Wheel */}
{totalPeople > 0 && (
<div
style={{
display: "flex",
flexDirection: "column",
marginTop: 20,
}}
>
{/* Spinner Visualization - Blank Spin Wheel */}
{totalPeople > 0 && (
<div
style={{
display: "flex",
flexDirection: "column",
gap: 12,
alignItems: "center",
}}
>
<div
style={{
position: "relative",
width: 200,
height: 200,
margin: "0 auto",
}}
>
<svg
width="200"
height="200"
viewBox="0 0 200 200"
style={{
transform: "rotate(-90deg)",
}}
>
{Array.from({ length: totalPeople }).map((_, index) => {
const anglePerSlice = 360 / totalPeople;
const startAngle = index * anglePerSlice;
const endAngle = (index + 1) * anglePerSlice;
const isSelected = index < payFor;
// Convert angles to radians
const startAngleRad = (startAngle * Math.PI) / 180;
const endAngleRad = (endAngle * Math.PI) / 180;
// Calculate path for pie slice (fit 200x200 viewBox)
const radius = 90;
const centerX = 100;
const centerY = 100;
const x1 = centerX + radius * Math.cos(startAngleRad);
const y1 = centerY + radius * Math.sin(startAngleRad);
const x2 = centerX + radius * Math.cos(endAngleRad);
const y2 = centerY + radius * Math.sin(endAngleRad);
const largeArcFlag = anglePerSlice > 180 ? 1 : 0;
const pathData = [
`M ${centerX} ${centerY}`,
`L ${x1} ${y1}`,
`A ${radius} ${radius} 0 ${largeArcFlag} 1 ${x2} ${y2}`,
"Z",
].join(" ");
return (
<path
key={index}
d={pathData}
fill={
isSelected ? "var(--primary)" : "rgba(0, 0, 0, 0.1)"
}
stroke="#fff"
strokeWidth="5"
/>
);
})}
</svg>
{/* Center circle with total bill amount */}
<div
style={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
// Keep the SVG at 200x200, but make the center content smaller
// so the wheel remains visible around it.
width: 160,
height: 160,
borderRadius: "50%",
backgroundColor: "var(--secondary-background)",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
zIndex: 10,
padding: 10,
}}
>
<div
style={{
fontSize: 20,
fontWeight: 600,
color: "var(--primary)",
lineHeight: 1.1,
textAlign: "center",
}}
>
<ArabicPrice
price={originalTotalBill}
style={{
fontSize: 20,
fontWeight: 600,
}}
/>
</div>
<ProText
style={{
fontSize: 11,
color: ProGray1,
marginTop: 6,
textAlign: "center",
lineHeight: 1.2,
fontWeight: 400,
}}
>
{t("splitBill.totalBill")}
</ProText>
</div>
</div>
</div>
)}
<div
style={{
display: "flex",
flexDirection: "column",
gap: 12,
alignItems: "center",
gap: "1rem",
padding: 20,
}}
>
<div
style={{
position: "relative",
width: 200,
height: 200,
margin: "0 auto",
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
gap: "1rem",
padding: 8,
}}
>
<svg
width="200"
height="200"
viewBox="0 0 200 200"
<ProText
style={{
transform: "rotate(-90deg)",
fontSize: "1rem",
marginTop: 3,
color: ProGray1,
}}
>
{Array.from({ length: totalPeople }).map((_, index) => {
const anglePerSlice = 360 / totalPeople;
const startAngle = index * anglePerSlice;
const endAngle = (index + 1) * anglePerSlice;
const isSelected = index < payFor;
{t("checkout.totalPeople")}
</ProText>
// Convert angles to radians
const startAngleRad = (startAngle * Math.PI) / 180;
const endAngleRad = (endAngle * Math.PI) / 180;
<TotalPeopleActions />
// Calculate path for pie slice (fit 200x200 viewBox)
const radius = 90;
const centerX = 100;
const centerY = 100;
const x1 = centerX + radius * Math.cos(startAngleRad);
const y1 = centerY + radius * Math.sin(startAngleRad);
const x2 = centerX + radius * Math.cos(endAngleRad);
const y2 = centerY + radius * Math.sin(endAngleRad);
const largeArcFlag = anglePerSlice > 180 ? 1 : 0;
const pathData = [
`M ${centerX} ${centerY}`,
`L ${x1} ${y1}`,
`A ${radius} ${radius} 0 ${largeArcFlag} 1 ${x2} ${y2}`,
"Z",
].join(" ");
return (
<path
key={index}
d={pathData}
fill={
isSelected ? "var(--primary)" : "rgba(0, 0, 0, 0.1)"
}
stroke="#fff"
strokeWidth="5"
/>
);
})}
</svg>
{/* Center circle with total bill amount */}
<div
<ProText
style={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
// Keep the SVG at 200x200, but make the center content smaller
// so the wheel remains visible around it.
width: 160,
height: 160,
borderRadius: "50%",
backgroundColor: "var(--secondary-background)",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
zIndex: 10,
padding: 10,
fontSize: "1rem",
marginTop: 3,
color: ProGray1,
}}
>
<div
style={{
fontSize: 20,
fontWeight: 600,
color: "var(--primary)",
lineHeight: 1.1,
textAlign: "center",
}}
>
<ArabicPrice
price={originalTotalBill}
style={{
fontSize: 20,
fontWeight: 600,
}}
/>
</div>
<ProText
style={{
fontSize: 11,
color: ProGray1,
marginTop: 6,
textAlign: "center",
lineHeight: 1.2,
fontWeight: 400,
}}
>
{t("splitBill.totalBill")}
</ProText>
</div>
{t("checkout.totalPeople")}
</ProText>
</div>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
gap: "1rem",
padding: 8,
}}
>
<ProText
style={{
fontSize: "1rem",
marginTop: 2,
color: ProGray1,
}}
>
{t("checkout.payFor")}
</ProText>
<PayForActions />
<ProText
style={{
fontSize: "1rem",
marginTop: 2,
color: ProGray1,
}}
>
{t("checkout.payFor")}
</ProText>
</div>
</div>
)}
<div
style={{
display: "flex",
flexDirection: "column",
gap: "1rem",
padding: 20,
}}
>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
gap: "1rem",
padding: 8,
flexDirection: "column",
backgroundColor: "var(--background)",
padding: 20,
opacity: 1,
gap: 8,
borderTopLeftRadius: 24,
borderTopRightRadius: 24,
paddingTop: 12,
paddingRight: 24,
paddingBottom: 24,
paddingLeft: 24,
}}
>
<ProText
style={{
fontSize: "1rem",
marginTop: 3,
color: ProGray1,
}}
>
{t("checkout.totalPeople")}
</ProText>
<TotalPeopleActions />
<ProText
style={{
fontSize: "1rem",
marginTop: 3,
color: ProGray1,
}}
>
{t("checkout.totalPeople")}
</ProText>
<div className={styles.summaryRow}>
<ProText
style={{
fontWeight: 400,
fontStyle: "Regular",
fontSize: 14,
lineHeight: "140%",
letterSpacing: "0%",
}}
>
{t("splitBill.yourShare")}
</ProText>
<ArabicPrice price={splitAmount} />
</div>
</div>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
gap: "1rem",
padding: 8,
gap: 12,
margin: 20,
}}
>
<ProText
<Button
style={{
fontSize: "1rem",
marginTop: 2,
color: ProGray1,
flex: 1,
backgroundColor: "#FEEDED",
color: "#DD4143",
boxShadow: "none",
border: "none",
}}
onClick={handleRemoveSplitWay}
>
{t("checkout.payFor")}
</ProText>
<PayForActions />
<ProText
style={{
fontSize: "1rem",
marginTop: 2,
color: ProGray1,
}}
{t("splitBill.removeSplit")}
</Button>
<Button
type="primary"
style={{ flex: 1, boxShadow: "none" }}
onClick={handleSave}
>
{t("checkout.payFor")}
</ProText>
{t("cart.save")}
</Button>
</div>
</div>
<div
style={{
display: "flex",
flexDirection: "column",
backgroundColor: "var(--background)",
padding: 20,
opacity: 1,
gap: 8,
borderTopLeftRadius: 24,
borderTopRightRadius: 24,
paddingTop: 12,
paddingRight: 24,
paddingBottom: 24,
paddingLeft: 24,
}}
>
<div className={styles.summaryRow}>
<ProText
style={{
fontWeight: 400,
fontStyle: "Regular",
fontSize: 14,
lineHeight: "140%",
letterSpacing: "0%",
}}
>
{t("splitBill.yourShare")}
</ProText>
<ArabicPrice price={splitAmount} />
</div>
</div>
<div
style={{
display: "flex",
gap: 12,
margin: 20,
}}
>
<Button
style={{
flex: 1,
backgroundColor: "#FEEDED",
color: "#DD4143",
boxShadow: "none",
border: "none",
}}
onClick={handleRemoveSplitWay}
>
{t("splitBill.removeSplit")}
</Button>
<Button
type="primary"
style={{ flex: 1, boxShadow: "none" }}
onClick={handleSave}
>
{t("cart.save")}
</Button>
</div>
</div>
</ProBottomSheet>
</ProBottomSheet>
<QRBottomSheet isOpen={isQROpen} onClose={() => setIsQROpen(false)} />
</>
);
}

View File

@@ -8,6 +8,7 @@ import ProText from "components/ProText";
import { selectCart, updateSplitBillAmount } from "features/order/orderSlice";
import { useAppDispatch, useAppSelector } from "redux/hooks";
import styles from "./SplitBill.module.css";
import { QRBottomSheet } from "./QRBottomSheet";
interface SplitBillChoiceBottomSheetProps {
isOpen: boolean;
@@ -25,7 +26,7 @@ export function PayForYourItemsChoiceBottomSheet({
const dispatch = useAppDispatch();
const { items } = useAppSelector(selectCart);
const [selectedItems, setSelectedItems] = useState<Set<string>>(new Set());
const [isQROpen, setIsQROpen] = useState(false);
// Calculate total for selected items
const selectedTotal = items
.filter((item) => selectedItems.has(item.uniqueId || item.id.toString()))
@@ -56,6 +57,7 @@ export function PayForYourItemsChoiceBottomSheet({
const handleSave = () => {
dispatch(updateSplitBillAmount(selectedTotal));
setIsQROpen(true);
onClose();
};
@@ -67,159 +69,162 @@ export function PayForYourItemsChoiceBottomSheet({
};
return (
<ProBottomSheet
isOpen={isOpen}
onClose={onClose}
title={t("splitBill.payForYourItems")}
showCloseButton={true}
initialSnap={1}
height={720}
snapPoints={[720]}
contentStyle={{ padding: 0 }}
>
<div
style={{
padding: 20,
display: "flex",
flexDirection: "column",
gap: 12,
maxHeight: "455px",
minHeight: "455px",
overflowY: "auto",
}}
>
{items.length === 0 ? (
<ProText
type="secondary"
style={{ textAlign: "center", padding: 20 }}
>
{t("cart.emptyCart")}
</ProText>
) : (
items.map((item) => {
const itemId = item.uniqueId || item.id.toString();
const isSelected = selectedItems.has(itemId);
const itemTotal = item.price * item.quantity;
return (
<>
<Card
key={itemId}
style={{
border: "none",
cursor: "pointer",
padding: 0,
}}
onClick={() => handleItemToggle(itemId)}
>
<div
style={{
display: "flex",
flexDirection: "row",
gap: 12,
alignItems: "center",
}}
>
<Image
src={item.image}
alt={item.name}
width={60}
height={60}
preview={false}
style={{
borderRadius: 8,
objectFit: "cover",
}}
/>
<div
style={{
flex: 1,
display: "flex",
flexDirection: "column",
gap: 4,
}}
>
<ProText style={{ fontSize: 14, fontWeight: 500 }}>
{item.name}
</ProText>
<ArabicPrice price={itemTotal} />
</div>
<div
style={{
width: 32,
height: 32,
minWidth: 32,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
onClick={(e) => e.stopPropagation()}
>
<Checkbox
className={styles.circleCheckbox}
checked={isSelected}
onChange={() => handleItemToggle(itemId)}
/>
</div>
</div>
</Card>
{item !== items[items.length - 1] && (
<Divider style={{ margin: "0" }} />
)}
</>
);
})
)}
</div>
<div
style={{
padding: 16,
backgroundColor: "rgba(255, 183, 0, 0.08)",
borderRadius: 8,
marginTop: 8,
}}
<>
<ProBottomSheet
isOpen={isOpen}
onClose={onClose}
title={t("splitBill.payForYourItems")}
showCloseButton={true}
initialSnap={1}
height={720}
snapPoints={[720]}
contentStyle={{ padding: 0 }}
>
<div
style={{
padding: 20,
display: "flex",
justifyContent: "space-between",
alignItems: "center",
flexDirection: "column",
gap: 12,
maxHeight: "455px",
minHeight: "455px",
overflowY: "auto",
}}
>
<ProText style={{ fontSize: 16, fontWeight: 600 }}>
{t("splitBill.selectedTotal")}:
</ProText>
<ArabicPrice price={selectedTotal} />
{items.length === 0 ? (
<ProText
type="secondary"
style={{ textAlign: "center", padding: 20 }}
>
{t("cart.emptyCart")}
</ProText>
) : (
items.map((item) => {
const itemId = item.uniqueId || item.id.toString();
const isSelected = selectedItems.has(itemId);
const itemTotal = item.price * item.quantity;
return (
<>
<Card
key={itemId}
style={{
border: "none",
cursor: "pointer",
padding: 0,
}}
onClick={() => handleItemToggle(itemId)}
>
<div
style={{
display: "flex",
flexDirection: "row",
gap: 12,
alignItems: "center",
}}
>
<Image
src={item.image}
alt={item.name}
width={60}
height={60}
preview={false}
style={{
borderRadius: 8,
objectFit: "cover",
}}
/>
<div
style={{
flex: 1,
display: "flex",
flexDirection: "column",
gap: 4,
}}
>
<ProText style={{ fontSize: 14, fontWeight: 500 }}>
{item.name}
</ProText>
<ArabicPrice price={itemTotal} />
</div>
<div
style={{
width: 32,
height: 32,
minWidth: 32,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
onClick={(e) => e.stopPropagation()}
>
<Checkbox
className={styles.circleCheckbox}
checked={isSelected}
onChange={() => handleItemToggle(itemId)}
/>
</div>
</div>
</Card>
{item !== items[items.length - 1] && (
<Divider style={{ margin: "0" }} />
)}
</>
);
})
)}
</div>
</div>
<div
style={{
display: "flex",
gap: 12,
margin: 20,
}}
>
<Button
<div
style={{
flex: 1,
backgroundColor: "#FEEDED",
color: "#DD4143",
boxShadow: "none",
border: "none",
padding: 16,
backgroundColor: "rgba(255, 183, 0, 0.08)",
borderRadius: 8,
marginTop: 8,
}}
onClick={handleRemoveSplitWay}
>
{t("splitBill.removeSplit")}
</Button>
<Button
type="primary"
style={{ flex: 1, boxShadow: "none" }}
onClick={handleSave}
disabled={selectedTotal === 0}
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<ProText style={{ fontSize: 16, fontWeight: 600 }}>
{t("splitBill.selectedTotal")}:
</ProText>
<ArabicPrice price={selectedTotal} />
</div>
</div>
<div
style={{
display: "flex",
gap: 12,
margin: 20,
}}
>
{t("cart.save")}
</Button>
</div>
</ProBottomSheet>
<Button
style={{
flex: 1,
backgroundColor: "#FEEDED",
color: "#DD4143",
boxShadow: "none",
border: "none",
}}
onClick={handleRemoveSplitWay}
>
{t("splitBill.removeSplit")}
</Button>
<Button
type="primary"
style={{ flex: 1, boxShadow: "none" }}
onClick={handleSave}
disabled={selectedTotal === 0}
>
{t("cart.save")}
</Button>
</div>
</ProBottomSheet>
<QRBottomSheet isOpen={isQROpen} onClose={() => setIsQROpen(false)} />
</>
);
}

View File

@@ -0,0 +1,123 @@
import { Button } from "antd";
import { ProBottomSheet } from "components/ProBottomSheet/ProBottomSheet.tsx";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import ProText from "components/ProText";
import QRIcon from "components/Icons/QRIcon";
interface QRBottomSheetProps {
isOpen: boolean;
onClose: () => void;
onSave?: (value: string) => void;
}
export function QRBottomSheet({
isOpen,
onClose,
}: QRBottomSheetProps) {
const { t } = useTranslation();
const [qrCode, setQRCode] = useState("");
const handleSave = () => {
onClose();
};
const handleCopyQRCode = () => {
navigator.clipboard.writeText(qrCode);
};
return (
<ProBottomSheet
isOpen={isOpen}
onClose={onClose}
title={t("splitBill.payWithQR")}
showCloseButton={true}
initialSnap={1}
height={430}
snapPoints={[430]}
contentStyle={{
padding: 0,
}}
>
<div
style={{
padding: "20px",
display: "flex",
flexDirection: "column",
gap: 20,
}}
>
<ProText
style={{
fontWeight: 400,
fontStyle: "Regular",
fontSize: 16,
lineHeight: "140%",
letterSpacing: "0%",
}}
>
{t("splitBill.inviteEveryonePayingWithYou")}
</ProText>
<div
style={{
display: "flex",
flexDirection: "column",
gap: 12,
alignItems: "center",
}}
>
<QRIcon />
<Button
style={{
width: 169,
height: 40,
borderRadius: 888,
gap: 16,
opacity: 1,
borderWidth: 1,
paddingTop: 8,
paddingRight: 32,
paddingBottom: 8,
paddingLeft: 32,
}}
onClick={handleCopyQRCode}
>
{t("splitBill.copyQRCode")}
</Button>
</div>
</div>
<div
style={{
display: "flex",
gap: 12,
margin: 20,
}}
>
<Button
style={{
flex: 1,
backgroundColor: "#FEEDED",
color: "#DD4143",
boxShadow: "none",
border: "none",
}}
onClick={onClose}
>
{t("splitBill.cancel")}
</Button>
<Button
type="primary"
style={{
flex: 1,
boxShadow: "none",
}}
onClick={handleSave}
>
{t("splitBill.done")}
</Button>
</div>
</ProBottomSheet>
);
}

View File

@@ -7,18 +7,19 @@ import { selectCart } from "features/order/orderSlice";
import { AddressSummary } from "pages/checkout/components/AddressSummary";
import BriefMenu from "pages/checkout/components/BriefMenu";
import { GiftCard } from "pages/checkout/components/GiftCard";
import PhoneCard from "pages/checkout/components/PhoneCard";
import { OrderType } from "pages/checkout/hooks/types";
import { useTranslation } from "react-i18next";
import { useAppSelector } from "redux/hooks";
import styles from "../address/address.module.css";
import PayButton from "./components/PayButton";
import CustomerInformationCard from "pages/checkout/components/CustomerInformationCard";
export default function PayPage() {
const { t } = useTranslation();
const [form] = Form.useForm();
const { phone, order, orderType } = useAppSelector(selectCart);
const { token } = useAppSelector((state) => state.auth);
return (
<>
<Form
@@ -54,7 +55,7 @@ export default function PayPage() {
{/* <GiftDetails /> */}
<BriefMenu />
<OrderSummary />
<PhoneCard />
{!token && <CustomerInformationCard />}
<PaymentMethods />
</Layout.Content>