add Cart model + add store fot save all methods
This commit is contained in:
@@ -10,13 +10,9 @@ import { useCart } from '../hook/useCart';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useGetProfile } from '@/app/[name]/(Profile)/profile/hooks/userProfileData';
|
import { useGetProfile } from '@/app/[name]/(Profile)/profile/hooks/userProfileData';
|
||||||
import { useGetCartItems } from '../hooks/useCartData';
|
import { useGetCartItems } from '../hooks/useCartData';
|
||||||
|
import { useCartStore } from '../store/Store';
|
||||||
|
|
||||||
interface CartSummaryProps {
|
const CartSummary = () => {
|
||||||
description?: string;
|
|
||||||
onDescriptionChange?: (value: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CartSummary = ({ description = '', onDescriptionChange }: CartSummaryProps) => {
|
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
@@ -27,6 +23,7 @@ const CartSummary = ({ description = '', onDescriptionChange }: CartSummaryProps
|
|||||||
const { items } = useCart();
|
const { items } = useCart();
|
||||||
const { data: cartData } = useGetCartItems(isSuccess);
|
const { data: cartData } = useGetCartItems(isSuccess);
|
||||||
const { t } = useTranslation('parallels', { keyPrefix: 'Cart' });
|
const { t } = useTranslation('parallels', { keyPrefix: 'Cart' });
|
||||||
|
const { description, setDescription } = useCartStore();
|
||||||
|
|
||||||
const cartFoods = React.useMemo(() => {
|
const cartFoods = React.useMemo(() => {
|
||||||
if (!foods.length) return [];
|
if (!foods.length) return [];
|
||||||
@@ -72,7 +69,7 @@ const CartSummary = ({ description = '', onDescriptionChange }: CartSummaryProps
|
|||||||
id='description'
|
id='description'
|
||||||
name='description'
|
name='description'
|
||||||
value={description}
|
value={description}
|
||||||
onChange={(e) => onDescriptionChange?.(e.target.value)}
|
onChange={(e) => setDescription(e.target.value)}
|
||||||
></textarea>
|
></textarea>
|
||||||
<span className='absolute top-4 right-2 px-2 bg-background text-foreground text-xs'></span>
|
<span className='absolute top-4 right-2 px-2 bg-background text-foreground text-xs'></span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -158,3 +158,9 @@ export const useGetCartItems = (enabled = true) => {
|
|||||||
enabled,
|
enabled,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useSaveAllMethod = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: api.saveAllMethod,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ const CartIndex = () => {
|
|||||||
const { t } = useTranslation('parallels', { keyPrefix: 'Cart' });
|
const { t } = useTranslation('parallels', { keyPrefix: 'Cart' });
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { clearCart } = useCart();
|
const { clearCart } = useCart();
|
||||||
const [description, setDescription] = React.useState('');
|
|
||||||
const [showClearConfirm, setShowClearConfirm] = React.useState(false);
|
const [showClearConfirm, setShowClearConfirm] = React.useState(false);
|
||||||
|
|
||||||
const handleClearCart = (e: React.MouseEvent) => {
|
const handleClearCart = (e: React.MouseEvent) => {
|
||||||
@@ -49,7 +48,7 @@ const CartIndex = () => {
|
|||||||
|
|
||||||
<div className='flex overflow-y-auto noscrollbar flex-col h-full pt-4 gap-4 pb-24' dir='rtl'>
|
<div className='flex overflow-y-auto noscrollbar flex-col h-full pt-4 gap-4 pb-24' dir='rtl'>
|
||||||
<CartItemsList />
|
<CartItemsList />
|
||||||
<CartSummary description={description} onDescriptionChange={setDescription} />
|
<CartSummary />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={showClearConfirm ? 'fixed inset-0 z-1001' : 'pointer-events-none fixed inset-0 z-1001'}>
|
<div className={showClearConfirm ? 'fixed inset-0 z-1001' : 'pointer-events-none fixed inset-0 z-1001'}>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { api } from "@/config/axios";
|
import { api } from "@/config/axios";
|
||||||
import { BulkCartItem, CartResponse } from "../types/Types";
|
import { BulkCartItem, CartResponse, SaveAllMethod } from "../types/Types";
|
||||||
|
|
||||||
export const bulkCart = async (params: BulkCartItem) => {
|
export const bulkCart = async (params: BulkCartItem) => {
|
||||||
const { data } = await api.post("/public/cart/items/bulk", params);
|
const { data } = await api.post("/public/cart/items/bulk", params);
|
||||||
@@ -30,3 +30,8 @@ export const getCartSummary = async () => {
|
|||||||
const { data } = await api.get("/public/cart/summary");
|
const { data } = await api.get("/public/cart/summary");
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const saveAllMethod = async (params: SaveAllMethod) => {
|
||||||
|
const { data } = await api.patch("/public/cart/all", params);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { create } from "zustand";
|
||||||
|
import { createJSONStorage, persist } from "zustand/middleware";
|
||||||
|
import { CartStoreType, SaveAllMethod } from "../types/Types";
|
||||||
|
|
||||||
|
export const useCartStore = create<CartStoreType>()(
|
||||||
|
persist(
|
||||||
|
(set, get) => ({
|
||||||
|
description: "",
|
||||||
|
setDescription: (value) => set({ description: value }),
|
||||||
|
deliveryMethodId: null,
|
||||||
|
setDeliveryMethodId: (value) => set({ deliveryMethodId: value }),
|
||||||
|
addressId: null,
|
||||||
|
setAddressId: (value) => set({ addressId: value }),
|
||||||
|
paymentMethodId: null,
|
||||||
|
setPaymentMethodId: (value) => set({ paymentMethodId: value }),
|
||||||
|
carAddress: null,
|
||||||
|
setCarAddress: (value) => set({ carAddress: value }),
|
||||||
|
reset: () =>
|
||||||
|
set({
|
||||||
|
description: "",
|
||||||
|
deliveryMethodId: null,
|
||||||
|
addressId: null,
|
||||||
|
paymentMethodId: null,
|
||||||
|
carAddress: null,
|
||||||
|
}),
|
||||||
|
getSaveAllMethodData: (): SaveAllMethod | null => {
|
||||||
|
const state = get();
|
||||||
|
if (!state.deliveryMethodId || !state.paymentMethodId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
description: state.description,
|
||||||
|
deliveryMethodId: state.deliveryMethodId,
|
||||||
|
...(state.addressId && { addressId: state.addressId }),
|
||||||
|
paymentMethodId: state.paymentMethodId,
|
||||||
|
...(state.carAddress && { carAddress: state.carAddress }),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: "cart-storage",
|
||||||
|
storage: createJSONStorage(() => localStorage),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
@@ -85,3 +85,40 @@ export interface CartFood {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type CartResponse = BaseResponse<CartData>;
|
export type CartResponse = BaseResponse<CartData>;
|
||||||
|
|
||||||
|
export type SaveAllMethod = {
|
||||||
|
description: string;
|
||||||
|
deliveryMethodId: string;
|
||||||
|
addressId?: string;
|
||||||
|
paymentMethodId: string;
|
||||||
|
carAddress?: {
|
||||||
|
carModel: string;
|
||||||
|
carColor: string;
|
||||||
|
plateNumber: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CartStoreType = {
|
||||||
|
description: string;
|
||||||
|
setDescription: (value: string) => void;
|
||||||
|
deliveryMethodId: string | null;
|
||||||
|
setDeliveryMethodId: (value: string | null) => void;
|
||||||
|
addressId: string | null;
|
||||||
|
setAddressId: (value: string | null) => void;
|
||||||
|
paymentMethodId: string | null;
|
||||||
|
setPaymentMethodId: (value: string | null) => void;
|
||||||
|
carAddress: {
|
||||||
|
carModel: string;
|
||||||
|
carColor: string;
|
||||||
|
plateNumber: string;
|
||||||
|
} | null;
|
||||||
|
setCarAddress: (
|
||||||
|
value: {
|
||||||
|
carModel: string;
|
||||||
|
carColor: string;
|
||||||
|
plateNumber: string;
|
||||||
|
} | null
|
||||||
|
) => void;
|
||||||
|
reset: () => void;
|
||||||
|
getSaveAllMethodData: () => SaveAllMethod | null;
|
||||||
|
};
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import Link from 'next/link';
|
|||||||
import { useParams } from 'next/navigation';
|
import { useParams } from 'next/navigation';
|
||||||
import { useEffect, useMemo } from 'react';
|
import { useEffect, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useSetAddressCart } from '../../hooks/useOrderData';
|
|
||||||
import { useCheckoutStore } from '../../store/Store';
|
import { useCheckoutStore } from '../../store/Store';
|
||||||
import useToggle from '@/hooks/helpers/useToggle';
|
import useToggle from '@/hooks/helpers/useToggle';
|
||||||
import { AddressSelectionModal } from './AddressSelectionModal';
|
import { AddressSelectionModal } from './AddressSelectionModal';
|
||||||
@@ -19,7 +18,6 @@ const formatAddress = (address: Address) => {
|
|||||||
|
|
||||||
export const AddressSection = () => {
|
export const AddressSection = () => {
|
||||||
|
|
||||||
const { mutate: setAddressCart } = useSetAddressCart();
|
|
||||||
const { setIsSelectedAddress, selectedAddressId, setSelectedAddressId, isSelectedShipment } = useCheckoutStore();
|
const { setIsSelectedAddress, selectedAddressId, setSelectedAddressId, isSelectedShipment } = useCheckoutStore();
|
||||||
const params = useParams<{ name: string; id: string }>();
|
const params = useParams<{ name: string; id: string }>();
|
||||||
const { t } = useTranslation('parallels', { keyPrefix: 'OrderDetail' });
|
const { t } = useTranslation('parallels', { keyPrefix: 'OrderDetail' });
|
||||||
@@ -35,24 +33,16 @@ export const AddressSection = () => {
|
|||||||
const defaultAddress = addresses.find(addr => addr.isDefault);
|
const defaultAddress = addresses.find(addr => addr.isDefault);
|
||||||
const addressToSet = defaultAddress || addresses.filter(addr => !addr.isDefault)[0];
|
const addressToSet = defaultAddress || addresses.filter(addr => !addr.isDefault)[0];
|
||||||
if (addressToSet) {
|
if (addressToSet) {
|
||||||
setAddressCart(addressToSet.id, {
|
|
||||||
onSuccess: () => {
|
|
||||||
setIsSelectedAddress(true);
|
setIsSelectedAddress(true);
|
||||||
setSelectedAddressId(addressToSet.id);
|
setSelectedAddressId(addressToSet.id);
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [isLoading, addresses, setAddressCart, setIsSelectedAddress, selectedAddressId, setSelectedAddressId, isSelectedShipment]);
|
}, [isLoading, addresses, setIsSelectedAddress, selectedAddressId, setSelectedAddressId, isSelectedShipment]);
|
||||||
|
|
||||||
const handleSelectAddress = (addressId: string) => {
|
const handleSelectAddress = (addressId: string) => {
|
||||||
setAddressCart(addressId, {
|
|
||||||
onSuccess: () => {
|
|
||||||
setIsSelectedAddress(true);
|
setIsSelectedAddress(true);
|
||||||
setSelectedAddressId(addressId);
|
setSelectedAddressId(addressId);
|
||||||
setModalVisible(false);
|
setModalVisible(false);
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// پیدا کردن آدرس انتخاب شده یا آدرس پیشفرض یا اولین آدرس غیر پیشفرض
|
// پیدا کردن آدرس انتخاب شده یا آدرس پیشفرض یا اولین آدرس غیر پیشفرض
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import InputField from '@/components/input/InputField';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useCheckoutStore } from '../../store/Store';
|
||||||
|
import { useCallback, useEffect } from 'react';
|
||||||
|
|
||||||
|
export const CarAddressSection = () => {
|
||||||
|
const { t } = useTranslation('parallels', { keyPrefix: 'OrderDetail' });
|
||||||
|
const { carAddress, setCarAddress } = useCheckoutStore();
|
||||||
|
|
||||||
|
const handleCarModelChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setCarAddress({
|
||||||
|
carModel: e.target.value,
|
||||||
|
carColor: carAddress?.carColor || '',
|
||||||
|
plateNumber: carAddress?.plateNumber || '',
|
||||||
|
});
|
||||||
|
}, [carAddress, setCarAddress]);
|
||||||
|
|
||||||
|
const handleCarColorChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setCarAddress({
|
||||||
|
carModel: carAddress?.carModel || '',
|
||||||
|
carColor: e.target.value,
|
||||||
|
plateNumber: carAddress?.plateNumber || '',
|
||||||
|
});
|
||||||
|
}, [carAddress, setCarAddress]);
|
||||||
|
|
||||||
|
const handlePlateNumberChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setCarAddress({
|
||||||
|
carModel: carAddress?.carModel || '',
|
||||||
|
carColor: carAddress?.carColor || '',
|
||||||
|
plateNumber: e.target.value,
|
||||||
|
});
|
||||||
|
}, [carAddress, setCarAddress]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!carAddress) {
|
||||||
|
setCarAddress({
|
||||||
|
carModel: '',
|
||||||
|
carColor: '',
|
||||||
|
plateNumber: '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [carAddress, setCarAddress]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="bg-container rounded-container box-shadow-normal p-4">
|
||||||
|
<div className="py-3">
|
||||||
|
<h3 className="text-sm2 font-medium leading-5 mb-4">
|
||||||
|
اطلاعات خودرو
|
||||||
|
</h3>
|
||||||
|
<div className="flex flex-col gap-4">
|
||||||
|
<InputField
|
||||||
|
htmlFor="carModel"
|
||||||
|
labelText="مدل خودرو"
|
||||||
|
placeholder="مثال: پژو 206"
|
||||||
|
value={carAddress?.carModel || ''}
|
||||||
|
onChange={handleCarModelChange}
|
||||||
|
className="bg-inherit"
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
htmlFor="carColor"
|
||||||
|
labelText="رنگ خودرو"
|
||||||
|
placeholder="مثال: سفید"
|
||||||
|
value={carAddress?.carColor || ''}
|
||||||
|
onChange={handleCarColorChange}
|
||||||
|
className="bg-inherit"
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
htmlFor="plateNumber"
|
||||||
|
labelText="شماره پلاک"
|
||||||
|
placeholder="مثال: 12ب34567"
|
||||||
|
value={carAddress?.plateNumber || ''}
|
||||||
|
onChange={handlePlateNumberChange}
|
||||||
|
className="bg-inherit"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -4,7 +4,7 @@ import { Card, Icon, Wallet2 } from 'iconsax-react';
|
|||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
||||||
import { useGetPaymentMethod, useSetPaymentMethod } from '../../hooks/useOrderData';
|
import { useGetPaymentMethod } from '../../hooks/useOrderData';
|
||||||
import { useCheckoutStore } from '../../store/Store';
|
import { useCheckoutStore } from '../../store/Store';
|
||||||
|
|
||||||
type PaymentSectionProps = {
|
type PaymentSectionProps = {
|
||||||
@@ -28,7 +28,6 @@ export const PaymentSection = ({ paymentType, onPaymentTypeChange }: PaymentSect
|
|||||||
const { t: tOrderDetail } = useTranslation('parallels', { keyPrefix: 'OrderDetail' });
|
const { t: tOrderDetail } = useTranslation('parallels', { keyPrefix: 'OrderDetail' });
|
||||||
const { t: tOrders } = useTranslation('orders');
|
const { t: tOrders } = useTranslation('orders');
|
||||||
const { data: paymentMethod } = useGetPaymentMethod();
|
const { data: paymentMethod } = useGetPaymentMethod();
|
||||||
const { mutate: setPaymentMethod } = useSetPaymentMethod();
|
|
||||||
const { setIsSelectedPayment } = useCheckoutStore();
|
const { setIsSelectedPayment } = useCheckoutStore();
|
||||||
|
|
||||||
const getPaymentMethodTranslation = useCallback((method: string, fallbackTitle: string) => {
|
const getPaymentMethodTranslation = useCallback((method: string, fallbackTitle: string) => {
|
||||||
@@ -59,11 +58,7 @@ export const PaymentSection = ({ paymentType, onPaymentTypeChange }: PaymentSect
|
|||||||
value={paymentType}
|
value={paymentType}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
onPaymentTypeChange(value);
|
onPaymentTypeChange(value);
|
||||||
setPaymentMethod(value, {
|
|
||||||
onSuccess: () => {
|
|
||||||
setIsSelectedPayment(true);
|
setIsSelectedPayment(true);
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
className='flex flex-col gap-6 mt-6'
|
className='flex flex-col gap-6 mt-6'
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import Combobox from '@/components/combobox/Combobox';
|
import Combobox from '@/components/combobox/Combobox';
|
||||||
import { Box } from 'iconsax-react';
|
import { Box } from 'iconsax-react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useGetShipmentMethod, useSetDeliveryMethod } from '../../hooks/useOrderData';
|
import { useGetShipmentMethod } from '../../hooks/useOrderData';
|
||||||
import { DeliveryMethod } from '../../types/Types';
|
import { DeliveryMethod } from '../../types/Types';
|
||||||
import { useCheckoutStore } from '../../store/Store';
|
import { useCheckoutStore } from '../../store/Store';
|
||||||
|
|
||||||
@@ -17,7 +17,6 @@ export const ShippingSection = ({ deliveryType, onDeliveryTypeChange }: Shipping
|
|||||||
const { t: tOrderDetail } = useTranslation('parallels', { keyPrefix: 'OrderDetail' });
|
const { t: tOrderDetail } = useTranslation('parallels', { keyPrefix: 'OrderDetail' });
|
||||||
const { t: tOrders } = useTranslation('orders');
|
const { t: tOrders } = useTranslation('orders');
|
||||||
const { data: shipmentMethod } = useGetShipmentMethod();
|
const { data: shipmentMethod } = useGetShipmentMethod();
|
||||||
const { mutate: setDeliveryMethod } = useSetDeliveryMethod();
|
|
||||||
const { setIsSelectedShipment } = useCheckoutStore();
|
const { setIsSelectedShipment } = useCheckoutStore();
|
||||||
|
|
||||||
const getDeliveryMethodTranslation = (method: string) => {
|
const getDeliveryMethodTranslation = (method: string) => {
|
||||||
@@ -50,13 +49,7 @@ export const ShippingSection = ({ deliveryType, onDeliveryTypeChange }: Shipping
|
|||||||
const selectedOption = options[i];
|
const selectedOption = options[i];
|
||||||
if (selectedOption) {
|
if (selectedOption) {
|
||||||
onDeliveryTypeChange(selectedOption.id);
|
onDeliveryTypeChange(selectedOption.id);
|
||||||
setDeliveryMethod(selectedOption.id, {
|
|
||||||
onSuccess: () => {
|
|
||||||
setTimeout(() => {
|
|
||||||
setIsSelectedShipment(true);
|
setIsSelectedShipment(true);
|
||||||
}, 200);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -6,14 +6,15 @@ import { ChevronLeft } from 'lucide-react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useCheckoutStore } from '../../store/Store';
|
import { useCheckoutStore } from '../../store/Store';
|
||||||
import { toast } from '@/components/Toast';
|
import { toast } from '@/components/Toast';
|
||||||
import { useConfirmOrder, useCreateOrder } from '../../hooks/useOrderData';
|
import { useCreateOrder } from '../../hooks/useOrderData';
|
||||||
import { extractErrorMessage } from '@/lib/func';
|
import { extractErrorMessage } from '@/lib/func';
|
||||||
import { useParams } from 'next/navigation';
|
import { useParams } from 'next/navigation';
|
||||||
import { useGetCartItems } from '@/app/[name]/(Dialogs)/cart/hooks/useCartData';
|
import { useGetCartItems, useSaveAllMethod } from '@/app/[name]/(Dialogs)/cart/hooks/useCartData';
|
||||||
import { useGetProfile } from '@/app/[name]/(Profile)/profile/hooks/userProfileData';
|
import { useGetProfile } from '@/app/[name]/(Profile)/profile/hooks/userProfileData';
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { useGetShipmentMethod } from '../../hooks/useOrderData';
|
import { useGetShipmentMethod } from '../../hooks/useOrderData';
|
||||||
import CartItemsList from '@/app/[name]/(Dialogs)/cart/components/CartItemsList';
|
import CartItemsList from '@/app/[name]/(Dialogs)/cart/components/CartItemsList';
|
||||||
|
import { useCartStore } from '@/app/[name]/(Dialogs)/cart/store/Store';
|
||||||
|
|
||||||
type SummarySectionProps = {
|
type SummarySectionProps = {
|
||||||
cartModal: boolean;
|
cartModal: boolean;
|
||||||
@@ -24,9 +25,10 @@ type SummarySectionProps = {
|
|||||||
export const SummarySection = ({ cartModal, onToggleCartModal, deliveryType }: SummarySectionProps) => {
|
export const SummarySection = ({ cartModal, onToggleCartModal, deliveryType }: SummarySectionProps) => {
|
||||||
|
|
||||||
const { t } = useTranslation('parallels', { keyPrefix: 'OrderDetail' });
|
const { t } = useTranslation('parallels', { keyPrefix: 'OrderDetail' });
|
||||||
const { isSelectedAddress, isSelectedShipment, isSelectedPayment } = useCheckoutStore();
|
const { isSelectedAddress, isSelectedShipment, isSelectedPayment, deliveryType: storeDeliveryType, paymentType, selectedAddressId, tableNumber, carAddress } = useCheckoutStore();
|
||||||
|
const { description } = useCartStore();
|
||||||
const { mutate: createOrder } = useCreateOrder();
|
const { mutate: createOrder } = useCreateOrder();
|
||||||
const { mutate: confirmOrder } = useConfirmOrder();
|
const { mutate: saveAllMethod } = useSaveAllMethod()
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const name = params.name as string;
|
const name = params.name as string;
|
||||||
const { isSuccess } = useGetProfile();
|
const { isSuccess } = useGetProfile();
|
||||||
@@ -42,6 +44,10 @@ export const SummarySection = ({ cartModal, onToggleCartModal, deliveryType }: S
|
|||||||
return selectedDeliveryMethod?.method === 'deliveryCourier';
|
return selectedDeliveryMethod?.method === 'deliveryCourier';
|
||||||
}, [selectedDeliveryMethod]);
|
}, [selectedDeliveryMethod]);
|
||||||
|
|
||||||
|
const isDeliveryCar = useMemo(() => {
|
||||||
|
return selectedDeliveryMethod?.method === 'deliveryCar';
|
||||||
|
}, [selectedDeliveryMethod]);
|
||||||
|
|
||||||
const formatPrice = useCallback(
|
const formatPrice = useCallback(
|
||||||
(value: number) => value.toLocaleString('fa-IR'),
|
(value: number) => value.toLocaleString('fa-IR'),
|
||||||
[]
|
[]
|
||||||
@@ -67,7 +73,54 @@ export const SummarySection = ({ cartModal, onToggleCartModal, deliveryType }: S
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
createOrder(undefined, {
|
if (isDeliveryCar) {
|
||||||
|
if (!carAddress || !carAddress.carModel || !carAddress.carColor || !carAddress.plateNumber) {
|
||||||
|
toast('لطفا اطلاعات خودرو را تکمیل کنید', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!storeDeliveryType || storeDeliveryType === '0' || !paymentType || paymentType === '0') {
|
||||||
|
toast('لطفا تمام اطلاعات را تکمیل کنید', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isDeliveryCar && !selectedAddressId) {
|
||||||
|
toast('لطفا آدرس را انتخاب کنید', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveAllMethodData = {
|
||||||
|
description: description || '',
|
||||||
|
deliveryMethodId: storeDeliveryType,
|
||||||
|
paymentMethodId: paymentType,
|
||||||
|
...(selectedAddressId && !isDeliveryCar && { addressId: selectedAddressId }),
|
||||||
|
...(carAddress && { carAddress }),
|
||||||
|
};
|
||||||
|
|
||||||
|
saveAllMethod(saveAllMethodData, {
|
||||||
|
onSuccess: () => {
|
||||||
|
const orderData: {
|
||||||
|
deliveryMethodId?: string;
|
||||||
|
paymentMethodId?: string;
|
||||||
|
addressId?: string;
|
||||||
|
tableNumber?: number;
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
if (storeDeliveryType && storeDeliveryType !== '0') {
|
||||||
|
orderData.deliveryMethodId = storeDeliveryType;
|
||||||
|
}
|
||||||
|
if (paymentType && paymentType !== '0') {
|
||||||
|
orderData.paymentMethodId = paymentType;
|
||||||
|
}
|
||||||
|
if (selectedAddressId && !isDeliveryCar) {
|
||||||
|
orderData.addressId = selectedAddressId;
|
||||||
|
}
|
||||||
|
if (tableNumber > 0) {
|
||||||
|
orderData.tableNumber = tableNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
createOrder(orderData, {
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
if (data?.data?.paymentUrl) {
|
if (data?.data?.paymentUrl) {
|
||||||
window.location.href = data?.data?.paymentUrl;
|
window.location.href = data?.data?.paymentUrl;
|
||||||
@@ -81,6 +134,11 @@ export const SummarySection = ({ cartModal, onToggleCartModal, deliveryType }: S
|
|||||||
toast(extractErrorMessage(error), 'error');
|
toast(extractErrorMessage(error), 'error');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast(extractErrorMessage(error), 'error');
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
import { MinusIcon, PlusIcon } from 'lucide-react';
|
import { MinusIcon, PlusIcon } from 'lucide-react';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useEffect } from 'react';
|
|
||||||
import { useSetTableNumber } from '../../hooks/useOrderData';
|
|
||||||
|
|
||||||
type TableSectionProps = {
|
type TableSectionProps = {
|
||||||
tableNumber: number;
|
tableNumber: number;
|
||||||
@@ -14,17 +12,6 @@ type TableSectionProps = {
|
|||||||
|
|
||||||
export const TableSection = ({ tableNumber, onIncrement, onDecrement }: TableSectionProps) => {
|
export const TableSection = ({ tableNumber, onIncrement, onDecrement }: TableSectionProps) => {
|
||||||
const { t } = useTranslation('parallels', { keyPrefix: 'OrderDetail' });
|
const { t } = useTranslation('parallels', { keyPrefix: 'OrderDetail' });
|
||||||
const { mutate: setTableNumber } = useSetTableNumber();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (tableNumber === 0) return;
|
|
||||||
|
|
||||||
const timer = setTimeout(() => {
|
|
||||||
setTableNumber(tableNumber);
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
return () => clearTimeout(timer);
|
|
||||||
}, [tableNumber, setTableNumber]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="bg-container rounded-container box-shadow-normal p-4 py-2">
|
<section className="bg-container rounded-container box-shadow-normal p-4 py-2">
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import useToggle from '@/hooks/helpers/useToggle';
|
import useToggle from '@/hooks/helpers/useToggle';
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||||
import { AddressSection } from './components/AddressSection';
|
import { AddressSection } from './components/AddressSection';
|
||||||
|
import { CarAddressSection } from './components/CarAddressSection';
|
||||||
import { CheckoutHeader } from './components/CheckoutHeader';
|
import { CheckoutHeader } from './components/CheckoutHeader';
|
||||||
import { CouponSection } from './components/CouponSection';
|
import { CouponSection } from './components/CouponSection';
|
||||||
import { PaymentSection } from './components/PaymentSection';
|
import { PaymentSection } from './components/PaymentSection';
|
||||||
import { ShippingSection } from './components/ShippingSection';
|
import { ShippingSection } from './components/ShippingSection';
|
||||||
import { SummarySection } from './components/SummarySection';
|
import { SummarySection } from './components/SummarySection';
|
||||||
import { TableSection } from './components/TableSection';
|
import { TableSection } from './components/TableSection';
|
||||||
import { useGetShipmentMethod, useSetAddressCart, useSetPaymentMethod } from '../hooks/useOrderData';
|
import { useGetShipmentMethod } from '../hooks/useOrderData';
|
||||||
import { useGetCartItems } from '@/app/[name]/(Dialogs)/cart/hooks/useCartData';
|
import { useGetCartItems } from '@/app/[name]/(Dialogs)/cart/hooks/useCartData';
|
||||||
import { useGetProfile } from '@/app/[name]/(Profile)/profile/hooks/userProfileData';
|
import { useGetProfile } from '@/app/[name]/(Profile)/profile/hooks/userProfileData';
|
||||||
import { useCheckoutStore } from '../store/Store';
|
import { useCheckoutStore } from '../store/Store';
|
||||||
@@ -17,28 +18,34 @@ import { useCheckoutStore } from '../store/Store';
|
|||||||
function OrderDetailInex() {
|
function OrderDetailInex() {
|
||||||
const { isSuccess } = useGetProfile();
|
const { isSuccess } = useGetProfile();
|
||||||
const { data: cartItems } = useGetCartItems(isSuccess);
|
const { data: cartItems } = useGetCartItems(isSuccess);
|
||||||
const [deliveryType, setDeliveryType] = React.useState<string>('0');
|
const { state: cartModal, toggle: toggleCartModal } = useToggle();
|
||||||
const [paymentType, setPaymentType] = React.useState<string>('0');
|
const { data: shipmentMethod } = useGetShipmentMethod();
|
||||||
|
const {
|
||||||
|
deliveryType,
|
||||||
|
setDeliveryType,
|
||||||
|
paymentType,
|
||||||
|
setPaymentType,
|
||||||
|
tableNumber,
|
||||||
|
setTableNumber,
|
||||||
|
setSelectedAddressId,
|
||||||
|
setIsSelectedAddress,
|
||||||
|
setIsSelectedPayment,
|
||||||
|
setIsSelectedShipment,
|
||||||
|
} = useCheckoutStore();
|
||||||
const [couponType, setCouponType] = React.useState<string>('0');
|
const [couponType, setCouponType] = React.useState<string>('0');
|
||||||
const [couponCode, setCouponCode] = React.useState<string>('');
|
const [couponCode, setCouponCode] = React.useState<string>('');
|
||||||
const [couponCodeError, setCouponCodeError] = React.useState<string>('');
|
const [couponCodeError, setCouponCodeError] = React.useState<string>('');
|
||||||
const [tableNumber, setTableNumber] = useState(0);
|
|
||||||
const { state: cartModal, toggle: toggleCartModal } = useToggle();
|
|
||||||
const { data: shipmentMethod } = useGetShipmentMethod();
|
|
||||||
const { mutate: setAddressCart } = useSetAddressCart();
|
|
||||||
const { mutate: setPaymentMethod } = useSetPaymentMethod();
|
|
||||||
const { setSelectedAddressId, setIsSelectedAddress, setIsSelectedPayment } = useCheckoutStore();
|
|
||||||
|
|
||||||
const incrementTableNumber = () => setTableNumber((prev) => prev + 1);
|
const incrementTableNumber = () => setTableNumber(tableNumber + 1);
|
||||||
const decrementTableNumber = () => setTableNumber((prev) => prev - 1);
|
const decrementTableNumber = () => setTableNumber(Math.max(0, tableNumber - 1));
|
||||||
|
|
||||||
const changeDeliveryType = useCallback((id: string) => {
|
const changeDeliveryType = useCallback((id: string) => {
|
||||||
setDeliveryType(id);
|
setDeliveryType(id);
|
||||||
}, []);
|
}, [setDeliveryType]);
|
||||||
|
|
||||||
const changePaymentType = useCallback((id: string) => {
|
const changePaymentType = useCallback((id: string) => {
|
||||||
setPaymentType(id);
|
setPaymentType(id);
|
||||||
}, []);
|
}, [setPaymentType]);
|
||||||
|
|
||||||
const changeCouponType = useCallback((id: string) => {
|
const changeCouponType = useCallback((id: string) => {
|
||||||
setCouponCode('');
|
setCouponCode('');
|
||||||
@@ -53,31 +60,24 @@ function OrderDetailInex() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (cartItems?.data?.deliveryMethodId) {
|
if (cartItems?.data?.deliveryMethodId) {
|
||||||
setDeliveryType(cartItems.data.deliveryMethodId);
|
setDeliveryType(cartItems.data.deliveryMethodId);
|
||||||
|
setIsSelectedShipment(true);
|
||||||
}
|
}
|
||||||
}, [cartItems?.data?.deliveryMethodId]);
|
}, [cartItems?.data?.deliveryMethodId, setDeliveryType, setIsSelectedShipment]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (cartItems?.data?.paymentMethodId) {
|
if (cartItems?.data?.paymentMethodId) {
|
||||||
setPaymentType(cartItems.data.paymentMethodId);
|
setPaymentType(cartItems.data.paymentMethodId);
|
||||||
setPaymentMethod(cartItems.data.paymentMethodId, {
|
|
||||||
onSuccess: () => {
|
|
||||||
setIsSelectedPayment(true);
|
setIsSelectedPayment(true);
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, [cartItems?.data?.paymentMethodId, setPaymentMethod, setIsSelectedPayment]);
|
}, [cartItems?.data?.paymentMethodId, setPaymentType, setIsSelectedPayment]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (cartItems?.data?.addressId) {
|
if (cartItems?.data?.addressId) {
|
||||||
const addressId = cartItems.data.addressId;
|
const addressId = cartItems.data.addressId;
|
||||||
setAddressCart(addressId, {
|
|
||||||
onSuccess: () => {
|
|
||||||
setIsSelectedAddress(true);
|
setIsSelectedAddress(true);
|
||||||
setSelectedAddressId(addressId ?? null);
|
setSelectedAddressId(addressId ?? null);
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, [cartItems?.data?.addressId, setAddressCart, setIsSelectedAddress, setSelectedAddressId]);
|
}, [cartItems?.data?.addressId, setIsSelectedAddress, setSelectedAddressId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (cartItems?.data?.coupon?.couponCode && cartItems.data.couponDiscount > 0) {
|
if (cartItems?.data?.coupon?.couponCode && cartItems.data.couponDiscount > 0) {
|
||||||
@@ -104,6 +104,10 @@ function OrderDetailInex() {
|
|||||||
onDeliveryTypeChange={changeDeliveryType}
|
onDeliveryTypeChange={changeDeliveryType}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{selectedDeliveryMethod?.method === 'deliveryCar' && (
|
||||||
|
<CarAddressSection />
|
||||||
|
)}
|
||||||
|
|
||||||
{shouldShowAddress && (
|
{shouldShowAddress && (
|
||||||
<AddressSection />
|
<AddressSection />
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -39,8 +39,16 @@ export const setPaymentMethod = async (id: string) => {
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createOrder = async (): Promise<CreateOrderResponse> => {
|
export const createOrder = async (orderData?: {
|
||||||
const { data } = await api.post<CreateOrderResponse>("/public/checkout");
|
deliveryMethodId?: string;
|
||||||
|
paymentMethodId?: string;
|
||||||
|
addressId?: string;
|
||||||
|
tableNumber?: number;
|
||||||
|
}): Promise<CreateOrderResponse> => {
|
||||||
|
const { data } = await api.post<CreateOrderResponse>(
|
||||||
|
"/public/checkout",
|
||||||
|
orderData
|
||||||
|
);
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
|
import { createJSONStorage, persist } from "zustand/middleware";
|
||||||
import { CheckoutStoreType } from "../types/Types";
|
import { CheckoutStoreType } from "../types/Types";
|
||||||
|
|
||||||
export const useCheckoutStore = create<CheckoutStoreType>((set) => ({
|
export const useCheckoutStore = create<CheckoutStoreType>()(
|
||||||
|
persist(
|
||||||
|
(set) => ({
|
||||||
isSelectedAddress: false,
|
isSelectedAddress: false,
|
||||||
setIsSelectedAddress: (value) => set({ isSelectedAddress: value }),
|
setIsSelectedAddress: (value) => set({ isSelectedAddress: value }),
|
||||||
selectedAddressId: null,
|
selectedAddressId: null,
|
||||||
@@ -10,4 +13,18 @@ export const useCheckoutStore = create<CheckoutStoreType>((set) => ({
|
|||||||
setIsSelectedPayment: (value) => set({ isSelectedPayment: value }),
|
setIsSelectedPayment: (value) => set({ isSelectedPayment: value }),
|
||||||
isSelectedShipment: false,
|
isSelectedShipment: false,
|
||||||
setIsSelectedShipment: (value) => set({ isSelectedShipment: value }),
|
setIsSelectedShipment: (value) => set({ isSelectedShipment: value }),
|
||||||
}));
|
deliveryType: "0",
|
||||||
|
setDeliveryType: (value) => set({ deliveryType: value }),
|
||||||
|
paymentType: "0",
|
||||||
|
setPaymentType: (value) => set({ paymentType: value }),
|
||||||
|
tableNumber: 0,
|
||||||
|
setTableNumber: (value) => set({ tableNumber: value }),
|
||||||
|
carAddress: null,
|
||||||
|
setCarAddress: (value) => set({ carAddress: value }),
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: "checkout-storage",
|
||||||
|
storage: createJSONStorage(() => localStorage),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|||||||
@@ -127,6 +127,24 @@ export type CheckoutStoreType = {
|
|||||||
setIsSelectedPayment: (value: boolean) => void;
|
setIsSelectedPayment: (value: boolean) => void;
|
||||||
isSelectedShipment: boolean;
|
isSelectedShipment: boolean;
|
||||||
setIsSelectedShipment: (value: boolean) => void;
|
setIsSelectedShipment: (value: boolean) => void;
|
||||||
|
deliveryType: string;
|
||||||
|
setDeliveryType: (value: string) => void;
|
||||||
|
paymentType: string;
|
||||||
|
setPaymentType: (value: string) => void;
|
||||||
|
tableNumber: number;
|
||||||
|
setTableNumber: (value: number) => void;
|
||||||
|
carAddress: {
|
||||||
|
carModel: string;
|
||||||
|
carColor: string;
|
||||||
|
plateNumber: string;
|
||||||
|
} | null;
|
||||||
|
setCarAddress: (
|
||||||
|
value: {
|
||||||
|
carModel: string;
|
||||||
|
carColor: string;
|
||||||
|
plateNumber: string;
|
||||||
|
} | null
|
||||||
|
) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface OrderUser {
|
export interface OrderUser {
|
||||||
|
|||||||
Reference in New Issue
Block a user