diff --git a/src/assets/locals/ar.json b/src/assets/locals/ar.json index d9b9f69..ead7256 100644 --- a/src/assets/locals/ar.json +++ b/src/assets/locals/ar.json @@ -268,10 +268,13 @@ "checkRequiredFields": "يرجى التحقق من الحقول المطلوبة" }, "checkout": { + "addCarDetails": "إضافة تفاصيل السيارة", + "soTheRestaurantCanRecognizeYourCarWhenYouArrive": "لتتمكن المطعم من التعرف على سيارتك عند وصولك.", "customerName": "اسم العميل", "paymentSummary": "ملخص الدفع", "holdayGiftCard": "هدية العيد", "messageIncluded": "الرسالة مضمنة", + "save":"حفظ", "to": "ل", "giftSummary": "ملخص الهدية", "customerInformation": "تفاصيل العميل", @@ -505,5 +508,9 @@ "add": "أضف", "senderNameRequired": "يجب أن يكون اسم المرسل مطلوب", "receiverNameRequired": "يجب أن يكون اسم المستلم مطلوب" + }, + "car":{ + "addCar":"إضافة سيارة", + "selectCar":"اختر السيارة" } } diff --git a/src/assets/locals/en.json b/src/assets/locals/en.json index 81fb41e..a9ce846 100644 --- a/src/assets/locals/en.json +++ b/src/assets/locals/en.json @@ -279,7 +279,10 @@ "checkRequiredFields": "Please check required fields" }, "checkout": { + "addCarDetails": "Add Car Details", + "soTheRestaurantCanRecognizeYourCarWhenYouArrive": "So the restaurant can recognize your car when you arrive.", "customerName": "Customer Name", + "save": "Save", "paymentSummary": "Payment Summary", "orderSummary": "Order Summary", "holdayGiftCard": "Holday gift card", @@ -517,5 +520,9 @@ "add": "Add", "senderNameRequired": "Sender name is required", "receiverNameRequired": "Receiver name is required" + }, + "car": { + "addCar": "Add Car", + "selectCar": "Select Car" } } diff --git a/src/components/CustomBottomSheet/CustomBottomSheet.module.css b/src/components/CustomBottomSheet/CustomBottomSheet.module.css index 5815189..829494a 100644 --- a/src/components/CustomBottomSheet/CustomBottomSheet.module.css +++ b/src/components/CustomBottomSheet/CustomBottomSheet.module.css @@ -17,8 +17,6 @@ width: 100%; } - - .serviceIcon path { stroke: #ea1f22; } @@ -32,3 +30,96 @@ width: 24px; height: 24px; } + +/* Make AntD checkbox look like a circular check indicator (scoped via CSS modules) */ +.circleCheckbox :global(.ant-checkbox-inner) { + width: 24px; + height: 24px; + border-radius: 50% !important; + border: 1.5px solid #d5d8da; + background: transparent; +} + +.circleCheckbox :global(.ant-checkbox-checked .ant-checkbox-inner) { + border-radius: 50% !important; + background: transparent; + border-color: #ffb700; +} + +/* Replace AntD checkmark with a filled inner circle when checked (match SVG) */ +.circleCheckbox :global(.ant-checkbox-inner::after) { + content: ""; + border: 0 !important; + transform: none !important; + width: 0; + height: 0; + left: 50%; + top: 50%; +} + +:global(.ant-app-rtl) .circleCheckbox :global(.ant-checkbox-inner::after) { + left: auto; + right: 50%; +} + +.circleCheckbox :global(.ant-checkbox-checked .ant-checkbox-inner::after) { + width: 18px; + height: 18px; + margin-left: -9px; + margin-top: -9px; + border-radius: 50%; + background: #ffb700; +} + +:global(.ant-app-rtl) + .circleCheckbox + :global(.ant-checkbox-checked .ant-checkbox-inner::after) { + margin-left: auto; + margin-right: -9px; +} + +/* Apply same circular style to Radio buttons */ +.radioCheckbox :global(.ant-radio-inner) { + width: 24px; + height: 24px; + border-radius: 50% !important; + border: 1.5px solid #d5d8da; + background: transparent; +} + +.radioCheckbox :global(.ant-radio-checked .ant-radio-inner) { + border-radius: 50% !important; + background: transparent; + border-color: #ffb700; +} + +.radioCheckbox :global(.ant-radio-inner::after) { + content: ""; + border: 0 !important; + transform: none !important; + width: 0; + height: 0; + left: 50%; + top: 50%; +} + +:global(.ant-app-rtl) .radioCheckbox :global(.ant-radio-inner::after) { + left: auto; + right: 50%; +} + +.radioCheckbox :global(.ant-radio-checked .ant-radio-inner::after) { + width: 18px; + height: 18px; + margin-left: -9px; + margin-top: -9px; + border-radius: 50%; + background: #ffb700; +} + +:global(.ant-app-rtl) + .radioCheckbox + :global(.ant-radio-checked .ant-radio-inner::after) { + margin-left: auto; + margin-right: -9px; +} diff --git a/src/components/CustomBottomSheet/TipBottomSheet.tsx b/src/components/CustomBottomSheet/TipBottomSheet.tsx index 57ce385..eb87ce5 100644 --- a/src/components/CustomBottomSheet/TipBottomSheet.tsx +++ b/src/components/CustomBottomSheet/TipBottomSheet.tsx @@ -1,10 +1,11 @@ -import { Button, Input } from "antd"; +import { Button, Input, InputNumber } from "antd"; import WaiterRewardingIcon from "components/Icons/waiter/WaiterRewardingIcon"; import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { ProBottomSheet } from "../ProBottomSheet/ProBottomSheet"; import { updateTip } from "features/order/orderSlice"; import { useAppDispatch } from "redux/hooks"; +import ProText from "components/ProText"; interface TipBottomSheetProps { isOpen: boolean; @@ -42,8 +43,8 @@ export function TipBottomSheet({ onClose={handleCancel} title={t("cart.tip")} initialSnap={1} - height={370} - snapPoints={[370]} + height={380} + snapPoints={[380]} >
-
+ + {t("cart.amount")} + - setValue(e.target.value)} + onChange={(value) => setValue(value?.toString() || "")} placeholder={t("cart.amount")} autoFocus={false} size="large" - style={{ height: 48 }} + style={{ height: 48, width: "100%", marginBottom: 8 }} + min={"0"} /> -
- diff --git a/src/components/Icons/CarIcon.tsx b/src/components/Icons/CarIcon.tsx new file mode 100644 index 0000000..fcc61e4 --- /dev/null +++ b/src/components/Icons/CarIcon.tsx @@ -0,0 +1,35 @@ +interface CarIconType { + className?: string; + onClick?: () => void; +} + +const CarIcon = ({ className, onClick }: CarIconType) => { + return ( + + + + + + ); +}; + +export default CarIcon; diff --git a/src/components/Icons/PlusIcon.tsx b/src/components/Icons/PlusIcon.tsx index dd6d36d..8de5842 100644 --- a/src/components/Icons/PlusIcon.tsx +++ b/src/components/Icons/PlusIcon.tsx @@ -1,15 +1,15 @@ interface PlusIconType { className?: string; onClick?: () => void; - dimesion?: string + dimension?: string color?: string } -const PlusIcon = ({ className, onClick, dimesion, color }: PlusIconType) => { +const PlusIcon = ({ className, onClick, dimension, color }: PlusIconType) => { return ( - {t("cart.addMore")} + {t("cart.addMore")}
diff --git a/src/pages/cart/components/RewardWaiterCard.tsx b/src/pages/cart/components/RewardWaiterCard.tsx index 2cb6160..df40896 100644 --- a/src/pages/cart/components/RewardWaiterCard.tsx +++ b/src/pages/cart/components/RewardWaiterCard.tsx @@ -161,19 +161,34 @@ export default function RewardWaiterCard() { iconPlacement="start" onClick={() => setIsTipOpen(true)} > - - {tip && !isDefaultTip ? tip : t("cart.other")} - + {tip && !isDefaultTip ? ( + + ) : ( + + {t("cart.other")} + + )} diff --git a/src/pages/checkout/checkout.module.css b/src/pages/checkout/checkout.module.css index e69de29..c5ea490 100644 --- a/src/pages/checkout/checkout.module.css +++ b/src/pages/checkout/checkout.module.css @@ -0,0 +1,13 @@ +.carCard { + gap: 20px; + opacity: 1; + border-radius: 6px; + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.plusIcon { + position: relative; + top: 2px; +} diff --git a/src/pages/checkout/components/CarBottomSheet.tsx b/src/pages/checkout/components/CarBottomSheet.tsx new file mode 100644 index 0000000..26fe9c6 --- /dev/null +++ b/src/pages/checkout/components/CarBottomSheet.tsx @@ -0,0 +1,112 @@ +import { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { ProBottomSheet } from "components/ProBottomSheet/ProBottomSheet"; +import { colors } from "ThemeConstants"; +import { Button, Card } from "antd"; +import CarRatioGroups from "./CarRatioGroups/CarRatioGroups"; +import PlusIcon from "components/Icons/PlusIcon"; +import styles from "../checkout.module.css"; + +interface CarBottomSheetProps { + isOpen: boolean; + onClose: () => void; +} + +export function CarBottomSheet({ isOpen, onClose }: CarBottomSheetProps) { + const { t } = useTranslation(); + const [value, setValue] = useState(null); + + const handleCancel = () => { + setValue(null); + onClose(); + }; + + const handleSave = () => { + onClose(); + setValue(value); + }; + + return ( + + + setValue(value)} + optionsStyle={{ + fontSize: 12, + fontWeight: 500, + color: "#5F6C7B", + }} + valueStyle={{ + fontSize: 12, + fontWeight: 500, + color: colors.primary, + }} + /> + + + +
+ +
+
+ ); +} diff --git a/src/pages/checkout/components/CarCard.tsx b/src/pages/checkout/components/CarCard.tsx new file mode 100644 index 0000000..f069767 --- /dev/null +++ b/src/pages/checkout/components/CarCard.tsx @@ -0,0 +1,78 @@ +import ProText from "components/ProText"; +import { useTranslation } from "react-i18next"; +import { useAppSelector } from "redux/hooks"; +import BackIcon from "components/Icons/BackIcon"; +import NextIcon from "components/Icons/NextIcon"; +import CarIcon from "components/Icons/CarIcon"; +import { Button, Card } from "antd"; +import styles from "../checkout.module.css"; +import { useState } from "react"; +import { CarBottomSheet } from "./CarBottomSheet"; + +export function CarCard() { + const { t } = useTranslation(); + const { isRTL } = useAppSelector((state) => state.locale); + const [isCarBottomSheetOpen, setIsCarBottomSheetOpen] = useState(false); + return ( + <> + { + setIsCarBottomSheetOpen(true); + }}> +
+
+
+ setIsCarBottomSheetOpen(false)} + /> + + ); +} diff --git a/src/pages/checkout/components/CarRatioGroups/CarRatioGroups.module.css b/src/pages/checkout/components/CarRatioGroups/CarRatioGroups.module.css new file mode 100644 index 0000000..43e2439 --- /dev/null +++ b/src/pages/checkout/components/CarRatioGroups/CarRatioGroups.module.css @@ -0,0 +1,122 @@ +.proRatioGroups :global(.ant-radio-wrapper:last-child) { + width: 100% !important; +} + +.proRatioGroups :global(.ant-radio-label) { + width: 100% !important; +} + +/* radio.module.css */ +.proRatioGroups :global(.ant-radio-inner) { + width: 24px !important; + height: 24px !important; + border-radius: 30px !important; +} + +.proRatioGroups :global(.ant-radio) { + width: 24px !important; + height: 24px !important; +} + +.circleCheckbox { + border: 1px solid #5f6c7b1f; + height: 62px; + justify-content: space-between; + opacity: 1; + border-radius: 888px; + padding: 8px 12px; + border-width: 1px; +} + +/* Make AntD checkbox look like a circular check indicator (scoped via CSS modules) */ +.circleCheckbox :global(.ant-checkbox-inner) { + width: 24px; + height: 24px; + border-radius: 50% !important; + border: 1.5px solid #d5d8da; + background: transparent; +} + +.circleCheckbox :global(.ant-checkbox-checked .ant-checkbox-inner) { + border-radius: 50% !important; + background: transparent; + border-color: #ffb700; +} + +/* Replace AntD checkmark with a filled inner circle when checked (match SVG) */ +.circleCheckbox :global(.ant-checkbox-inner::after) { + content: ""; + border: 0 !important; + transform: none !important; + width: 0; + height: 0; + left: 50%; + top: 50%; +} + +:global(.ant-app-rtl) .circleCheckbox :global(.ant-checkbox-inner::after) { + left: auto; + right: 50%; +} + +.circleCheckbox :global(.ant-checkbox-checked .ant-checkbox-inner::after) { + width: 18px; + height: 18px; + margin-left: -9px; + margin-top: -9px; + border-radius: 50%; + background: #ffb700; +} + +:global(.ant-app-rtl) + .circleCheckbox + :global(.ant-checkbox-checked .ant-checkbox-inner::after) { + margin-left: auto; + margin-right: -9px; +} + +/* Apply same circular style to Radio buttons */ +.circleCheckbox :global(.ant-radio-inner) { + width: 24px; + height: 24px; + border-radius: 50% !important; + border: 1.5px solid #d5d8da; + background: transparent; +} + +.circleCheckbox :global(.ant-radio-checked .ant-radio-inner) { + border-radius: 50% !important; + background: transparent; + border-color: #ffb700; +} + +.circleCheckbox :global(.ant-radio-inner::after) { + content: ""; + border: 0 !important; + transform: none !important; + width: 0; + height: 0; + left: 50%; + top: 50%; +} + +:global(.ant-app-rtl) .circleCheckbox :global(.ant-radio-inner::after) { + left: auto; + right: 50%; +} + +.circleCheckbox :global(.ant-radio-checked .ant-radio-inner::after) { + width: 18px; + height: 18px; + margin-left: -9px; + margin-top: -9px; + border-radius: 50%; + background: #ffb700; +} + +:global(.ant-app-rtl) + .circleCheckbox + :global(.ant-radio-checked .ant-radio-inner::after) { + margin-left: auto; + margin-right: -9px; +} diff --git a/src/pages/checkout/components/CarRatioGroups/CarRatioGroups.tsx b/src/pages/checkout/components/CarRatioGroups/CarRatioGroups.tsx new file mode 100644 index 0000000..7595b14 --- /dev/null +++ b/src/pages/checkout/components/CarRatioGroups/CarRatioGroups.tsx @@ -0,0 +1,132 @@ +import { Button, Card, Divider, Radio, RadioChangeEvent, Space } from "antd"; +import ProText from "components/ProText"; +import styles from "./CarRatioGroups.module.css"; +import { useTranslation } from "react-i18next"; +import CarIcon from "components/Icons/CarIcon"; + +interface CarRatioGroupsProps { + options: { label: string; value: string; price?: string }[]; + onRatioClick?: (value: string) => void; + onChange?: (e: RadioChangeEvent) => void; + value?: string; + optionsStyle?: React.CSSProperties; + valueStyle?: React.CSSProperties; + showDivider?: boolean; +} + +const CarRatioGroups = ({ + options, + onRatioClick, + onChange, + value, + optionsStyle, + valueStyle, + showDivider = false, + ...props +}: CarRatioGroupsProps) => { + const { t } = useTranslation(); + const handleChange = (e: RadioChangeEvent) => { + console.log(e.target.value); + // If onChange is provided (from Form.Item), use it + if (onChange) { + onChange(e); + } + // Also call onRatioClick if provided (for backward compatibility) + if (onRatioClick) { + onRatioClick(e.target.value); + } + }; + + return ( +
+ + + {options.map((option) => ( + <> + +
+
+
+ + Optima + + + + 42322, blue + +
+
+ +
+
+ {showDivider && options.length !== options.length - 1 && ( + + )} + + ))} +
+
+
+ ); +}; + +export default CarRatioGroups; diff --git a/src/pages/checkout/page.tsx b/src/pages/checkout/page.tsx index 83db955..829471f 100644 --- a/src/pages/checkout/page.tsx +++ b/src/pages/checkout/page.tsx @@ -20,6 +20,7 @@ import CustomerInformationCard from "./components/CustomerInformationCard"; import Ads1 from "components/Ads/Ads1"; import TimeEstimateCard from "pages/cart/components/timeEstimate/TimeEstimateCard"; import { useEffect } from "react"; +import { CarCard } from "./components/CarCard"; export default function CheckoutPage() { const { t } = useTranslation(); @@ -46,6 +47,7 @@ export default function CheckoutPage() { {(orderType === OrderType.Pickup || orderType === OrderType.ScheduledOrder) && } + {orderType === OrderType.Pickup && } {orderType === OrderType.Gift && } {!token && }