working on gift flow
This commit is contained in:
@@ -45,8 +45,8 @@ export function GiftBottomSheet({
|
||||
title={t("address.giftDetails")}
|
||||
showCloseButton={false}
|
||||
initialSnap={1}
|
||||
height={"90vh"}
|
||||
snapPoints={["90vh"]}
|
||||
height={755}
|
||||
snapPoints={[755]}
|
||||
>
|
||||
<Form
|
||||
layout="vertical"
|
||||
@@ -114,6 +114,7 @@ export function GiftBottomSheet({
|
||||
autoFocus={false}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="senderPhone"
|
||||
label={t("address.senderPhone")}
|
||||
@@ -130,6 +131,22 @@ export function GiftBottomSheet({
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="senderEmail"
|
||||
label={t("address.senderEmail")}
|
||||
rules={[{ required: true, message: "" }]}
|
||||
colon={false}
|
||||
>
|
||||
<Input
|
||||
placeholder={t("address.senderEmail")}
|
||||
size="large"
|
||||
style={{
|
||||
fontSize: 14,
|
||||
}}
|
||||
autoFocus={false}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="isSecret"
|
||||
rules={[{ required: true, message: "" }]}
|
||||
|
||||
@@ -17,8 +17,8 @@ const CancelIcon = ({ className, onClick }: CancelIconType) => {
|
||||
<path
|
||||
d="M13.6666 5.68425L7.99998 8.83239M7.99998 8.83239L2.33331 5.68425M7.99998 8.83239L8 15.1657M14 9.16575L14 6.12671C14 5.89828 14 5.78407 13.9663 5.6822C13.9366 5.59208 13.8879 5.50936 13.8236 5.43957C13.7509 5.36068 13.651 5.30521 13.4514 5.19428L8.51802 2.45353C8.32895 2.3485 8.23442 2.29598 8.1343 2.27539C8.0457 2.25716 7.95431 2.25716 7.8657 2.27539C7.76559 2.29598 7.67105 2.3485 7.48198 2.45353L2.54865 5.19428C2.34897 5.30521 2.24912 5.36068 2.17642 5.43957C2.11211 5.50936 2.06343 5.59208 2.03366 5.6822C2 5.78407 2 5.89828 2 6.12671V11.5381C2 11.7665 2 11.8808 2.03366 11.9826C2.06343 12.0727 2.11211 12.1555 2.17642 12.2253C2.24912 12.3041 2.34897 12.3596 2.54865 12.4706L7.48198 15.2113C7.67105 15.3163 7.76559 15.3688 7.8657 15.3894C7.95431 15.4077 8.0457 15.4077 8.1343 15.3894C8.23442 15.3688 8.32895 15.3163 8.51802 15.2113L8.66667 15.1287M5 3.83241L11 7.16575M11 11.4991L14.3333 14.8324M14.3333 11.4991L11 14.8324"
|
||||
stroke="#FF6F59"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
@@ -10,10 +10,9 @@ import { colors, ProGray1 } from "../../ThemeConstants";
|
||||
import ProInputCard from "../ProInputCard/ProInputCard";
|
||||
import styles from "./PaymentMethods.module.css";
|
||||
|
||||
|
||||
const PaymentMethods = () => {
|
||||
const { t } = useTranslation();
|
||||
const { paymentMethod } = useAppSelector(selectCart);
|
||||
const { paymentMethod, orderType } = useAppSelector(selectCart);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const options: {
|
||||
@@ -23,11 +22,15 @@ const PaymentMethods = () => {
|
||||
icon?: React.ReactNode;
|
||||
style?: React.CSSProperties;
|
||||
}[] = [
|
||||
{
|
||||
label: t("checkout.creditDebitCard"),
|
||||
value: "creditDebitCard",
|
||||
price: t("checkout.expiresIn") + ":12/26",
|
||||
},
|
||||
...(orderType !== "gift"
|
||||
? [
|
||||
{
|
||||
label: t("checkout.creditDebitCard"),
|
||||
value: "creditDebitCard",
|
||||
price: t("checkout.expiresIn") + ":12/26",
|
||||
},
|
||||
]
|
||||
: []),
|
||||
|
||||
{
|
||||
label: t("checkout.differentCard"),
|
||||
|
||||
@@ -218,7 +218,7 @@ export function ProBottomSheet({
|
||||
const contentStyle: React.CSSProperties = {
|
||||
flex: 1,
|
||||
overflow: "auto",
|
||||
padding: "20px",
|
||||
padding: "0 20px",
|
||||
backgroundColor: themeName === "dark" ? "#0a0a0a" : "#ffffff",
|
||||
color: themeName === "dark" ? "#ffffff" : "#000000",
|
||||
};
|
||||
|
||||
@@ -30,6 +30,7 @@ export interface GiftDetailsType {
|
||||
message: string;
|
||||
senderName: string;
|
||||
senderPhone: string;
|
||||
senderEmail: string;
|
||||
isSecret: boolean;
|
||||
}
|
||||
|
||||
@@ -50,6 +51,7 @@ interface CartState {
|
||||
collectionMethod: string;
|
||||
phone: string;
|
||||
paymentMethod: string;
|
||||
orderType: string;
|
||||
}
|
||||
|
||||
// localStorage keys
|
||||
@@ -69,6 +71,7 @@ export const CART_STORAGE_KEYS = {
|
||||
COLLECTION_METHOD: 'fascano_collection_method',
|
||||
PHONE: 'fascano_phone',
|
||||
PAYMENT_METHOD: 'fascano_payment_method',
|
||||
ORDER_TYPE: 'fascano_order_type',
|
||||
} as const;
|
||||
|
||||
// Utility functions for localStorage
|
||||
@@ -101,6 +104,7 @@ const initialState: CartState = {
|
||||
collectionMethod: getFromLocalStorage(CART_STORAGE_KEYS.COLLECTION_METHOD, ""),
|
||||
phone: getFromLocalStorage(CART_STORAGE_KEYS.PHONE, ""),
|
||||
paymentMethod: getFromLocalStorage(CART_STORAGE_KEYS.PAYMENT_METHOD, ""),
|
||||
orderType: getFromLocalStorage(CART_STORAGE_KEYS.ORDER_TYPE, ""),
|
||||
};
|
||||
|
||||
const orderSlice = createSlice({
|
||||
@@ -164,7 +168,7 @@ const orderSlice = createSlice({
|
||||
state.paymentMethod = "";
|
||||
// Clear all cart data from localStorage
|
||||
if (typeof window !== 'undefined') {
|
||||
Object.values(CART_STORAGE_KEYS).forEach(key => {
|
||||
Object.values(CART_STORAGE_KEYS).filter(key => key !== CART_STORAGE_KEYS.ORDER_TYPE).forEach(key => {
|
||||
localStorage.removeItem(key);
|
||||
});
|
||||
}
|
||||
@@ -296,6 +300,14 @@ const orderSlice = createSlice({
|
||||
localStorage.setItem(CART_STORAGE_KEYS.PAYMENT_METHOD, JSON.stringify(state.paymentMethod));
|
||||
}
|
||||
},
|
||||
updateOrderType(state, action: PayloadAction<string>) {
|
||||
state.orderType = action.payload;
|
||||
|
||||
// Sync to localStorage
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem(CART_STORAGE_KEYS.ORDER_TYPE, JSON.stringify(state.orderType));
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -320,6 +332,7 @@ export const {
|
||||
updateCollectionMethod,
|
||||
updatePhone,
|
||||
updatePaymentMethod,
|
||||
updateOrderType,
|
||||
reset,
|
||||
} = orderSlice.actions;
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { updateSpecialRequest, selectCart } from "features/order/orderSlice.ts";
|
||||
import { message, Input } from "antd";
|
||||
import { RightOutlined } from "@ant-design/icons";
|
||||
import { Input } from "antd";
|
||||
import ProInputCard from "components/ProInputCard/ProInputCard.tsx";
|
||||
import { selectCart, updateSpecialRequest } from "features/order/orderSlice.ts";
|
||||
import useBreakPoint from "hooks/useBreakPoint.ts";
|
||||
import { BottomSheet } from "pages/cart/components/specialRequest/BottomSheet.tsx";
|
||||
import { Dialog } from "pages/cart/components/specialRequest/Dialog.tsx";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAppDispatch, useAppSelector } from "redux/hooks.ts";
|
||||
import ProInputCard from "components/ProInputCard/ProInputCard.tsx";
|
||||
import { RightOutlined } from "@ant-design/icons";
|
||||
import { BottomSheet } from "pages/cart/components/specialRequest/BottomSheet.tsx";
|
||||
import { useState } from "react";
|
||||
import useBreakPoint from "hooks/useBreakPoint.ts";
|
||||
import { Dialog } from "pages/cart/components/specialRequest/Dialog.tsx";
|
||||
import styles from "./SpecialRequestCard.module.css";
|
||||
|
||||
export default function SpecialRequestCard() {
|
||||
@@ -20,7 +20,6 @@ export default function SpecialRequestCard() {
|
||||
|
||||
const handleSpecialRequestSave = (value: string) => {
|
||||
dispatch(updateSpecialRequest(value));
|
||||
message.success(t("cart.specialRequest") + " " + t("updatedSuccessfully"));
|
||||
};
|
||||
|
||||
const handleSpecialRequestClose = () => {
|
||||
|
||||
@@ -19,7 +19,7 @@ export const AddressSummary = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { location } = useAppSelector(selectCart);
|
||||
const [isMapBottomSheetOpen, setIsMapBottomSheetOpen] = useState(false);
|
||||
const orderType = useMemo(() => localStorage.getItem("orderType"), []); // Default to delivery for now
|
||||
const { orderType } = useAppSelector(selectCart) // Default to delivery for now
|
||||
|
||||
const handleLocationSave = useCallback(
|
||||
(locationString: string) => {
|
||||
|
||||
@@ -11,7 +11,7 @@ import styles from "../../address/address.module.css";
|
||||
export default function BriefMenu() {
|
||||
const { tables, items } = useAppSelector(selectCart);
|
||||
const { t } = useTranslation();
|
||||
const orderType = useMemo(() => localStorage.getItem("orderType"), []);
|
||||
const { orderType } = useAppSelector(selectCart)
|
||||
|
||||
const menuItems = useMemo(
|
||||
() =>
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { Button, FormInstance } from "antd";
|
||||
import { selectCart } from "features/order/orderSlice";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { useAppSelector } from "redux/hooks";
|
||||
import styles from "../../address/address.module.css";
|
||||
import useOrder from "../hooks/useOrder";
|
||||
|
||||
export default function CheckoutButton({ form }: { form: FormInstance }) {
|
||||
const { t } = useTranslation();
|
||||
const orderType = useMemo(() => localStorage.getItem("orderType"), []);
|
||||
const { orderType } = useAppSelector(selectCart)
|
||||
const navigate = useNavigate();
|
||||
const { handleCreateOrder } = useOrder();
|
||||
const { id } = useParams();
|
||||
|
||||
@@ -23,8 +23,7 @@ export const GiftDetails = () => {
|
||||
const { giftDetails } = useAppSelector(selectCart);
|
||||
const [isOfficeBottomSheetOpen, setIsOfficeBottomSheetOpen] = useState(false);
|
||||
const [isInfoButtonSheetOpen, setIsInfoButtonSheetOpen] = useState(false);
|
||||
|
||||
const orderType = useMemo(() => localStorage.getItem("orderType"), []);
|
||||
const { orderType } = useAppSelector(selectCart);
|
||||
|
||||
const handleGiftDetailsSave = useCallback(
|
||||
(giftDetailsData: GiftDetailsType) => {
|
||||
|
||||
@@ -20,7 +20,7 @@ export const OfficeDetails = () => {
|
||||
const { officeDetails } = useAppSelector(selectCart);
|
||||
const [isOfficeBottomSheetOpen, setIsOfficeBottomSheetOpen] = useState(false);
|
||||
|
||||
const orderType = useMemo(() => localStorage.getItem("orderType"), []);
|
||||
const { orderType } = useAppSelector(selectCart)
|
||||
|
||||
const handleOfficeDetailsSave = useCallback(
|
||||
(officeDetailsData: OfficeDetailsType) => {
|
||||
|
||||
@@ -5,9 +5,9 @@ import GoldenHouseIcon from "components/Icons/address/GoldenHouseIcon";
|
||||
import RoomServiceIcon from "components/Icons/address/RoomServiceIcon";
|
||||
import ProText from "components/ProText";
|
||||
import {
|
||||
RoomDetailsType,
|
||||
selectCart,
|
||||
updateRoomDetails,
|
||||
RoomDetailsType,
|
||||
selectCart,
|
||||
updateRoomDetails,
|
||||
} from "features/order/orderSlice";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -20,7 +20,7 @@ export const RoomDetails = () => {
|
||||
const { roomDetails } = useAppSelector(selectCart);
|
||||
const [isRoomBottomSheetOpen, setIsRoomBottomSheetOpen] = useState(false);
|
||||
|
||||
const orderType = useMemo(() => localStorage.getItem("orderType"), []);
|
||||
const { orderType } = useAppSelector(selectCart)
|
||||
|
||||
const handleRoomDetailsSave = useCallback(
|
||||
(roomDetailsData: RoomDetailsType) => {
|
||||
|
||||
@@ -7,21 +7,30 @@ import { useAppDispatch, useAppSelector } from "redux/hooks";
|
||||
export default function PhoneCard() {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const { phone } = useAppSelector(selectCart);
|
||||
const { phone, orderType } = useAppSelector(selectCart);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ProInputCard title={t("checkout.phoneNumber")}>
|
||||
<Form.Item name="phone" required rules={[{ required: true, message: t("checkout.pleaseEnterPhoneNumber") }]}>
|
||||
<Input
|
||||
placeholder={t("checkout.phoneNumber")}
|
||||
size="large"
|
||||
autoFocus={false}
|
||||
style={{ padding: "7px 11px", height: 50, borderRadius: 888 }}
|
||||
value={phone}
|
||||
onChange={(e) => dispatch(updatePhone(e.target.value))}
|
||||
/>
|
||||
</Form.Item>
|
||||
</ProInputCard>
|
||||
</>
|
||||
orderType !== "gift" && (
|
||||
<>
|
||||
<ProInputCard title={t("checkout.phoneNumber")}>
|
||||
<Form.Item
|
||||
name="phone"
|
||||
required
|
||||
rules={[
|
||||
{ required: true, message: t("checkout.pleaseEnterPhoneNumber") },
|
||||
]}
|
||||
>
|
||||
<Input
|
||||
placeholder={t("checkout.phoneNumber")}
|
||||
size="large"
|
||||
autoFocus={false}
|
||||
style={{ padding: "7px 11px", height: 50, borderRadius: 888 }}
|
||||
value={phone}
|
||||
onChange={(e) => dispatch(updatePhone(e.target.value))}
|
||||
/>
|
||||
</Form.Item>
|
||||
</ProInputCard>
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,11 +5,12 @@ import { useTranslation } from "react-i18next";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { useCreateOrderMutation } from "redux/api/others";
|
||||
import { useAppDispatch, useAppSelector } from "redux/hooks";
|
||||
import { PAYMENT_CONFIRMATION_URL } from "utils/constants";
|
||||
import { Customer } from "../../otp/types";
|
||||
|
||||
export default function useOrder() {
|
||||
const dispatch = useAppDispatch();
|
||||
const router = useNavigate();
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation();
|
||||
const { id } = useParams();
|
||||
const restaurantID = localStorage.getItem("restaurantID");
|
||||
@@ -25,19 +26,22 @@ export default function useOrder() {
|
||||
phone,
|
||||
estimateTime,
|
||||
officeDetails,
|
||||
orderType,
|
||||
giftDetails,
|
||||
} = useAppSelector(selectCart);
|
||||
|
||||
const [createOrder] = useCreateOrderMutation();
|
||||
|
||||
const handleCreateOrder = useCallback(() => {
|
||||
createOrder({
|
||||
phone: mobilenumber || phone,
|
||||
phone: mobilenumber || phone || giftDetails?.senderPhone,
|
||||
couponID: coupon,
|
||||
discountAmount: 0,
|
||||
comment: specialRequest,
|
||||
timeslot: "",
|
||||
table_id: tables,
|
||||
deliveryType: "table",
|
||||
deliveryType: orderType,
|
||||
dineType: orderType,
|
||||
type: "table-pickup",
|
||||
user_id: id,
|
||||
restorant_id: restaurantID,
|
||||
@@ -61,13 +65,33 @@ export default function useOrder() {
|
||||
),
|
||||
useWallet: 0,
|
||||
tip,
|
||||
...(orderType === "gift"
|
||||
? {
|
||||
receiverName: giftDetails?.receiverName,
|
||||
receiverPhone: giftDetails?.receiverPhone,
|
||||
specialMessage: giftDetails?.message,
|
||||
keepNameSecret: giftDetails?.isSecret,
|
||||
senderEmail: giftDetails?.senderEmail,
|
||||
senderPhone: giftDetails?.senderPhone,
|
||||
senderName: giftDetails?.senderName,
|
||||
}
|
||||
: {}),
|
||||
})
|
||||
.then((res: any) => {
|
||||
if (res.error)
|
||||
message.error(res.error.data.message || t("order.createOrderFailed"));
|
||||
else {
|
||||
if (orderType === "gift")
|
||||
// navigate(`/${PAYMENT_CONFIRMATION_URL}/${res.data.result.orderID}`, {
|
||||
// replace: false,
|
||||
// });
|
||||
window.location.href = `${PAYMENT_CONFIRMATION_URL}/${res.data.result.orderID}`;
|
||||
// window.open(
|
||||
// `${PAYMENT_CONFIRMATION_URL}/${res.data.result.orderID}`,
|
||||
// );
|
||||
else navigate(`/${id}/order/${res.data.result.orderID}`);
|
||||
dispatch(clearCart());
|
||||
router(`/${id}/order/${res.data.result.orderID}`);
|
||||
localStorage.setItem("orderID", res.data.result.orderID);
|
||||
}
|
||||
})
|
||||
.catch((error: any) => {
|
||||
@@ -77,9 +101,17 @@ export default function useOrder() {
|
||||
createOrder,
|
||||
mobilenumber,
|
||||
phone,
|
||||
giftDetails?.senderPhone,
|
||||
giftDetails?.receiverName,
|
||||
giftDetails?.receiverPhone,
|
||||
giftDetails?.message,
|
||||
giftDetails?.isSecret,
|
||||
giftDetails?.senderEmail,
|
||||
giftDetails?.senderName,
|
||||
coupon,
|
||||
specialRequest,
|
||||
tables,
|
||||
orderType,
|
||||
id,
|
||||
restaurantID,
|
||||
items,
|
||||
@@ -88,8 +120,8 @@ export default function useOrder() {
|
||||
estimateTime,
|
||||
tip,
|
||||
t,
|
||||
navigate,
|
||||
dispatch,
|
||||
router,
|
||||
]);
|
||||
return { handleCreateOrder };
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { Button, Grid } from "antd";
|
||||
import { Button } from "antd";
|
||||
import DineInIcon from "components/Icons/DineInIcon";
|
||||
import DownIcon from "components/Icons/DownIcon";
|
||||
import PickupIcon from "components/Icons/PickupIcon";
|
||||
import useBreakPoint from "hooks/useBreakPoint";
|
||||
import styles from "../menu.module.css";
|
||||
|
||||
interface ResponsiveServicesProps {
|
||||
@@ -17,13 +18,12 @@ interface ResponsiveServicesProps {
|
||||
};
|
||||
}
|
||||
|
||||
const { useBreakpoint } = Grid;
|
||||
|
||||
export default function ResponsiveServices({ orderType, translations }: ResponsiveServicesProps) {
|
||||
const { xs } = useBreakpoint();
|
||||
const { isMobile } = useBreakPoint();
|
||||
|
||||
// Hide pickup service if screen width is less than 400px (insufficient for 3 services)
|
||||
const shouldHidePickup = xs;
|
||||
const shouldHidePickup = isMobile;
|
||||
|
||||
return (
|
||||
<div className={styles.services}>
|
||||
|
||||
@@ -33,8 +33,6 @@ export default function OrderPage() {
|
||||
},
|
||||
);
|
||||
|
||||
console.log(orderDetails);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ProHeader>{t("order.title")}</ProHeader>
|
||||
|
||||
@@ -9,9 +9,10 @@ import SendGiftIcon from "components/Icons/SendGiftIcon";
|
||||
import ToOfficeIcon from "components/Icons/ToOfficeIcon";
|
||||
import ToRoomIcon from "components/Icons/ToRoomIcon";
|
||||
import ProTitle from "components/ProTitle";
|
||||
import { updateOrderType } from "features/order/orderSlice";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import { useAppSelector } from "redux/hooks";
|
||||
import { useAppDispatch, useAppSelector } from "redux/hooks";
|
||||
import styles from "./restaurant.module.css";
|
||||
|
||||
interface RestaurantServicesProps {
|
||||
@@ -37,7 +38,8 @@ export default function RestaurantServices({
|
||||
const { t } = useTranslation();
|
||||
const { isRTL } = useAppSelector((state) => state.locale);
|
||||
const id = localStorage.getItem("restaurantName");
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const services = [
|
||||
...((dineIn && [
|
||||
{
|
||||
@@ -161,7 +163,7 @@ export default function RestaurantServices({
|
||||
to={s?.href}
|
||||
key={s?.id}
|
||||
onClick={() => {
|
||||
localStorage.setItem("orderType", s?.id);
|
||||
dispatch(updateOrderType(s?.id));
|
||||
}}
|
||||
style={{
|
||||
width: "100%",
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
ORDERS_URL,
|
||||
PRODUCTS_AND_CATEGORIES_URL,
|
||||
RESTAURANT_DETAILS_URL,
|
||||
TABLES_URL,
|
||||
TABLES_URL
|
||||
} from "utils/constants";
|
||||
|
||||
import { OrderDetails } from "pages/checkout/hooks/types";
|
||||
|
||||
@@ -102,3 +102,4 @@ export const TABLES_URL = `${BASE_URL}restaurant/getTables`;
|
||||
export const LOGIN_URL = `${API_BASE_URL}login`;
|
||||
export const SEND_OTP_URL = `${API_BASE_URL}sendOtp`;
|
||||
export const CONFIRM_OTP_URL = `${API_BASE_URL}confirmOtp`;
|
||||
export const PAYMENT_CONFIRMATION_URL = `https://menu.fascano.com/payment/confirmation`;
|
||||
|
||||
Reference in New Issue
Block a user