From ae35774e1f94e2346be65be18b652d321a822399 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Thu, 18 Dec 2025 11:58:02 +0330 Subject: [PATCH] add Cart model + add store fot save all methods --- .../(Dialogs)/cart/components/CartSummary.tsx | 11 +-- .../(Dialogs)/cart/hooks/useCartData.ts | 6 ++ src/app/[name]/(Dialogs)/cart/page.tsx | 3 +- .../(Dialogs)/cart/service/CartService.ts | 7 +- src/app/[name]/(Dialogs)/cart/store/Store.ts | 45 ++++++++++ src/app/[name]/(Dialogs)/cart/types/Types.ts | 37 +++++++++ .../[id]/components/AddressSection.tsx | 22 ++--- .../[id]/components/CarAddressSection.tsx | 81 ++++++++++++++++++ .../[id]/components/PaymentSection.tsx | 9 +- .../[id]/components/ShippingSection.tsx | 11 +-- .../[id]/components/SummarySection.tsx | 82 ++++++++++++++++--- .../checkout/[id]/components/TableSection.tsx | 13 --- .../(Dialogs)/order/checkout/[id]/page.tsx | 60 +++++++------- .../order/checkout/service/OrderService.ts | 12 ++- .../(Dialogs)/order/checkout/store/Store.ts | 37 ++++++--- .../(Dialogs)/order/checkout/types/Types.ts | 18 ++++ 16 files changed, 347 insertions(+), 107 deletions(-) create mode 100644 src/app/[name]/(Dialogs)/cart/store/Store.ts create mode 100644 src/app/[name]/(Dialogs)/order/checkout/[id]/components/CarAddressSection.tsx diff --git a/src/app/[name]/(Dialogs)/cart/components/CartSummary.tsx b/src/app/[name]/(Dialogs)/cart/components/CartSummary.tsx index c261917..4c029ad 100644 --- a/src/app/[name]/(Dialogs)/cart/components/CartSummary.tsx +++ b/src/app/[name]/(Dialogs)/cart/components/CartSummary.tsx @@ -10,13 +10,9 @@ import { useCart } from '../hook/useCart'; import { useTranslation } from 'react-i18next'; import { useGetProfile } from '@/app/[name]/(Profile)/profile/hooks/userProfileData'; import { useGetCartItems } from '../hooks/useCartData'; +import { useCartStore } from '../store/Store'; -interface CartSummaryProps { - description?: string; - onDescriptionChange?: (value: string) => void; -} - -const CartSummary = ({ description = '', onDescriptionChange }: CartSummaryProps) => { +const CartSummary = () => { const params = useParams(); const router = useRouter(); const pathname = usePathname(); @@ -27,6 +23,7 @@ const CartSummary = ({ description = '', onDescriptionChange }: CartSummaryProps const { items } = useCart(); const { data: cartData } = useGetCartItems(isSuccess); const { t } = useTranslation('parallels', { keyPrefix: 'Cart' }); + const { description, setDescription } = useCartStore(); const cartFoods = React.useMemo(() => { if (!foods.length) return []; @@ -72,7 +69,7 @@ const CartSummary = ({ description = '', onDescriptionChange }: CartSummaryProps id='description' name='description' value={description} - onChange={(e) => onDescriptionChange?.(e.target.value)} + onChange={(e) => setDescription(e.target.value)} > diff --git a/src/app/[name]/(Dialogs)/cart/hooks/useCartData.ts b/src/app/[name]/(Dialogs)/cart/hooks/useCartData.ts index 49e49a1..8ea5c89 100644 --- a/src/app/[name]/(Dialogs)/cart/hooks/useCartData.ts +++ b/src/app/[name]/(Dialogs)/cart/hooks/useCartData.ts @@ -158,3 +158,9 @@ export const useGetCartItems = (enabled = true) => { enabled, }); }; + +export const useSaveAllMethod = () => { + return useMutation({ + mutationFn: api.saveAllMethod, + }); +}; diff --git a/src/app/[name]/(Dialogs)/cart/page.tsx b/src/app/[name]/(Dialogs)/cart/page.tsx index b8f1584..c6952b2 100644 --- a/src/app/[name]/(Dialogs)/cart/page.tsx +++ b/src/app/[name]/(Dialogs)/cart/page.tsx @@ -13,7 +13,6 @@ const CartIndex = () => { const { t } = useTranslation('parallels', { keyPrefix: 'Cart' }); const router = useRouter(); const { clearCart } = useCart(); - const [description, setDescription] = React.useState(''); const [showClearConfirm, setShowClearConfirm] = React.useState(false); const handleClearCart = (e: React.MouseEvent) => { @@ -49,7 +48,7 @@ const CartIndex = () => {
- +
diff --git a/src/app/[name]/(Dialogs)/cart/service/CartService.ts b/src/app/[name]/(Dialogs)/cart/service/CartService.ts index 05bba95..8e14a79 100644 --- a/src/app/[name]/(Dialogs)/cart/service/CartService.ts +++ b/src/app/[name]/(Dialogs)/cart/service/CartService.ts @@ -1,5 +1,5 @@ import { api } from "@/config/axios"; -import { BulkCartItem, CartResponse } from "../types/Types"; +import { BulkCartItem, CartResponse, SaveAllMethod } from "../types/Types"; export const bulkCart = async (params: BulkCartItem) => { 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"); return data; }; + +export const saveAllMethod = async (params: SaveAllMethod) => { + const { data } = await api.patch("/public/cart/all", params); + return data; +}; diff --git a/src/app/[name]/(Dialogs)/cart/store/Store.ts b/src/app/[name]/(Dialogs)/cart/store/Store.ts new file mode 100644 index 0000000..ea682e2 --- /dev/null +++ b/src/app/[name]/(Dialogs)/cart/store/Store.ts @@ -0,0 +1,45 @@ +import { create } from "zustand"; +import { createJSONStorage, persist } from "zustand/middleware"; +import { CartStoreType, SaveAllMethod } from "../types/Types"; + +export const useCartStore = create()( + 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), + } + ) +); diff --git a/src/app/[name]/(Dialogs)/cart/types/Types.ts b/src/app/[name]/(Dialogs)/cart/types/Types.ts index fda3183..983506c 100644 --- a/src/app/[name]/(Dialogs)/cart/types/Types.ts +++ b/src/app/[name]/(Dialogs)/cart/types/Types.ts @@ -85,3 +85,40 @@ export interface CartFood { } export type CartResponse = BaseResponse; + +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; +}; diff --git a/src/app/[name]/(Dialogs)/order/checkout/[id]/components/AddressSection.tsx b/src/app/[name]/(Dialogs)/order/checkout/[id]/components/AddressSection.tsx index 45d0a72..ecc2faa 100644 --- a/src/app/[name]/(Dialogs)/order/checkout/[id]/components/AddressSection.tsx +++ b/src/app/[name]/(Dialogs)/order/checkout/[id]/components/AddressSection.tsx @@ -8,7 +8,6 @@ import Link from 'next/link'; import { useParams } from 'next/navigation'; import { useEffect, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { useSetAddressCart } from '../../hooks/useOrderData'; import { useCheckoutStore } from '../../store/Store'; import useToggle from '@/hooks/helpers/useToggle'; import { AddressSelectionModal } from './AddressSelectionModal'; @@ -19,7 +18,6 @@ const formatAddress = (address: Address) => { export const AddressSection = () => { - const { mutate: setAddressCart } = useSetAddressCart(); const { setIsSelectedAddress, selectedAddressId, setSelectedAddressId, isSelectedShipment } = useCheckoutStore(); const params = useParams<{ name: string; id: string }>(); const { t } = useTranslation('parallels', { keyPrefix: 'OrderDetail' }); @@ -35,24 +33,16 @@ export const AddressSection = () => { const defaultAddress = addresses.find(addr => addr.isDefault); const addressToSet = defaultAddress || addresses.filter(addr => !addr.isDefault)[0]; if (addressToSet) { - setAddressCart(addressToSet.id, { - onSuccess: () => { - setIsSelectedAddress(true); - setSelectedAddressId(addressToSet.id); - }, - }); + setIsSelectedAddress(true); + setSelectedAddressId(addressToSet.id); } } - }, [isLoading, addresses, setAddressCart, setIsSelectedAddress, selectedAddressId, setSelectedAddressId, isSelectedShipment]); + }, [isLoading, addresses, setIsSelectedAddress, selectedAddressId, setSelectedAddressId, isSelectedShipment]); const handleSelectAddress = (addressId: string) => { - setAddressCart(addressId, { - onSuccess: () => { - setIsSelectedAddress(true); - setSelectedAddressId(addressId); - setModalVisible(false); - }, - }); + setIsSelectedAddress(true); + setSelectedAddressId(addressId); + setModalVisible(false); }; // پیدا کردن آدرس انتخاب شده یا آدرس پیش‌فرض یا اولین آدرس غیر پیش‌فرض diff --git a/src/app/[name]/(Dialogs)/order/checkout/[id]/components/CarAddressSection.tsx b/src/app/[name]/(Dialogs)/order/checkout/[id]/components/CarAddressSection.tsx new file mode 100644 index 0000000..dcbf960 --- /dev/null +++ b/src/app/[name]/(Dialogs)/order/checkout/[id]/components/CarAddressSection.tsx @@ -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) => { + setCarAddress({ + carModel: e.target.value, + carColor: carAddress?.carColor || '', + plateNumber: carAddress?.plateNumber || '', + }); + }, [carAddress, setCarAddress]); + + const handleCarColorChange = useCallback((e: React.ChangeEvent) => { + setCarAddress({ + carModel: carAddress?.carModel || '', + carColor: e.target.value, + plateNumber: carAddress?.plateNumber || '', + }); + }, [carAddress, setCarAddress]); + + const handlePlateNumberChange = useCallback((e: React.ChangeEvent) => { + setCarAddress({ + carModel: carAddress?.carModel || '', + carColor: carAddress?.carColor || '', + plateNumber: e.target.value, + }); + }, [carAddress, setCarAddress]); + + useEffect(() => { + if (!carAddress) { + setCarAddress({ + carModel: '', + carColor: '', + plateNumber: '', + }); + } + }, [carAddress, setCarAddress]); + + return ( +
+
+

+ اطلاعات خودرو +

+
+ + + +
+
+
+ ); +}; diff --git a/src/app/[name]/(Dialogs)/order/checkout/[id]/components/PaymentSection.tsx b/src/app/[name]/(Dialogs)/order/checkout/[id]/components/PaymentSection.tsx index 780175f..04e8864 100644 --- a/src/app/[name]/(Dialogs)/order/checkout/[id]/components/PaymentSection.tsx +++ b/src/app/[name]/(Dialogs)/order/checkout/[id]/components/PaymentSection.tsx @@ -4,7 +4,7 @@ import { Card, Icon, Wallet2 } from 'iconsax-react'; import { useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; -import { useGetPaymentMethod, useSetPaymentMethod } from '../../hooks/useOrderData'; +import { useGetPaymentMethod } from '../../hooks/useOrderData'; import { useCheckoutStore } from '../../store/Store'; type PaymentSectionProps = { @@ -28,7 +28,6 @@ export const PaymentSection = ({ paymentType, onPaymentTypeChange }: PaymentSect const { t: tOrderDetail } = useTranslation('parallels', { keyPrefix: 'OrderDetail' }); const { t: tOrders } = useTranslation('orders'); const { data: paymentMethod } = useGetPaymentMethod(); - const { mutate: setPaymentMethod } = useSetPaymentMethod(); const { setIsSelectedPayment } = useCheckoutStore(); const getPaymentMethodTranslation = useCallback((method: string, fallbackTitle: string) => { @@ -59,11 +58,7 @@ export const PaymentSection = ({ paymentType, onPaymentTypeChange }: PaymentSect value={paymentType} onValueChange={(value) => { onPaymentTypeChange(value); - setPaymentMethod(value, { - onSuccess: () => { - setIsSelectedPayment(true); - }, - }); + setIsSelectedPayment(true); }} className='flex flex-col gap-6 mt-6' > diff --git a/src/app/[name]/(Dialogs)/order/checkout/[id]/components/ShippingSection.tsx b/src/app/[name]/(Dialogs)/order/checkout/[id]/components/ShippingSection.tsx index fa8390c..ec08fd7 100644 --- a/src/app/[name]/(Dialogs)/order/checkout/[id]/components/ShippingSection.tsx +++ b/src/app/[name]/(Dialogs)/order/checkout/[id]/components/ShippingSection.tsx @@ -3,7 +3,7 @@ import Combobox from '@/components/combobox/Combobox'; import { Box } from 'iconsax-react'; import { useTranslation } from 'react-i18next'; -import { useGetShipmentMethod, useSetDeliveryMethod } from '../../hooks/useOrderData'; +import { useGetShipmentMethod } from '../../hooks/useOrderData'; import { DeliveryMethod } from '../../types/Types'; import { useCheckoutStore } from '../../store/Store'; @@ -17,7 +17,6 @@ export const ShippingSection = ({ deliveryType, onDeliveryTypeChange }: Shipping const { t: tOrderDetail } = useTranslation('parallels', { keyPrefix: 'OrderDetail' }); const { t: tOrders } = useTranslation('orders'); const { data: shipmentMethod } = useGetShipmentMethod(); - const { mutate: setDeliveryMethod } = useSetDeliveryMethod(); const { setIsSelectedShipment } = useCheckoutStore(); const getDeliveryMethodTranslation = (method: string) => { @@ -50,13 +49,7 @@ export const ShippingSection = ({ deliveryType, onDeliveryTypeChange }: Shipping const selectedOption = options[i]; if (selectedOption) { onDeliveryTypeChange(selectedOption.id); - setDeliveryMethod(selectedOption.id, { - onSuccess: () => { - setTimeout(() => { - setIsSelectedShipment(true); - }, 200); - }, - }); + setIsSelectedShipment(true); } }} /> diff --git a/src/app/[name]/(Dialogs)/order/checkout/[id]/components/SummarySection.tsx b/src/app/[name]/(Dialogs)/order/checkout/[id]/components/SummarySection.tsx index 7887800..0112130 100644 --- a/src/app/[name]/(Dialogs)/order/checkout/[id]/components/SummarySection.tsx +++ b/src/app/[name]/(Dialogs)/order/checkout/[id]/components/SummarySection.tsx @@ -6,14 +6,15 @@ import { ChevronLeft } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { useCheckoutStore } from '../../store/Store'; import { toast } from '@/components/Toast'; -import { useConfirmOrder, useCreateOrder } from '../../hooks/useOrderData'; +import { useCreateOrder } from '../../hooks/useOrderData'; import { extractErrorMessage } from '@/lib/func'; 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 { useCallback, useMemo } from 'react'; import { useGetShipmentMethod } from '../../hooks/useOrderData'; import CartItemsList from '@/app/[name]/(Dialogs)/cart/components/CartItemsList'; +import { useCartStore } from '@/app/[name]/(Dialogs)/cart/store/Store'; type SummarySectionProps = { cartModal: boolean; @@ -24,9 +25,10 @@ type SummarySectionProps = { export const SummarySection = ({ cartModal, onToggleCartModal, deliveryType }: SummarySectionProps) => { 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: confirmOrder } = useConfirmOrder(); + const { mutate: saveAllMethod } = useSaveAllMethod() const params = useParams(); const name = params.name as string; const { isSuccess } = useGetProfile(); @@ -42,6 +44,10 @@ export const SummarySection = ({ cartModal, onToggleCartModal, deliveryType }: S return selectedDeliveryMethod?.method === 'deliveryCourier'; }, [selectedDeliveryMethod]); + const isDeliveryCar = useMemo(() => { + return selectedDeliveryMethod?.method === 'deliveryCar'; + }, [selectedDeliveryMethod]); + const formatPrice = useCallback( (value: number) => value.toLocaleString('fa-IR'), [] @@ -67,15 +73,67 @@ export const SummarySection = ({ cartModal, onToggleCartModal, deliveryType }: S return; } - createOrder(undefined, { - onSuccess: (data) => { - if (data?.data?.paymentUrl) { - window.location.href = data?.data?.paymentUrl; - toast('در حال ریدایرکت به صفحه پرداخت...', 'success'); - } else { - window.location.href = `/${name}/verify/${data?.data?.order?.id}`; - toast('سفارش با موفقیت ثبت شد', 'success'); + 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) => { + if (data?.data?.paymentUrl) { + window.location.href = data?.data?.paymentUrl; + toast('در حال ریدایرکت به صفحه پرداخت...', 'success'); + } else { + window.location.href = `/${name}/verify/${data?.data?.order?.id}`; + toast('سفارش با موفقیت ثبت شد', 'success'); + } + }, + onError: (error) => { + toast(extractErrorMessage(error), 'error'); + } + }); }, onError: (error) => { toast(extractErrorMessage(error), 'error'); diff --git a/src/app/[name]/(Dialogs)/order/checkout/[id]/components/TableSection.tsx b/src/app/[name]/(Dialogs)/order/checkout/[id]/components/TableSection.tsx index d72bd08..cc8bdf3 100644 --- a/src/app/[name]/(Dialogs)/order/checkout/[id]/components/TableSection.tsx +++ b/src/app/[name]/(Dialogs)/order/checkout/[id]/components/TableSection.tsx @@ -3,8 +3,6 @@ import { MinusIcon, PlusIcon } from 'lucide-react'; import { motion } from 'framer-motion'; import { useTranslation } from 'react-i18next'; -import { useEffect } from 'react'; -import { useSetTableNumber } from '../../hooks/useOrderData'; type TableSectionProps = { tableNumber: number; @@ -14,17 +12,6 @@ type TableSectionProps = { export const TableSection = ({ tableNumber, onIncrement, onDecrement }: TableSectionProps) => { 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 (
diff --git a/src/app/[name]/(Dialogs)/order/checkout/[id]/page.tsx b/src/app/[name]/(Dialogs)/order/checkout/[id]/page.tsx index a0728ad..2921afc 100644 --- a/src/app/[name]/(Dialogs)/order/checkout/[id]/page.tsx +++ b/src/app/[name]/(Dialogs)/order/checkout/[id]/page.tsx @@ -1,15 +1,16 @@ 'use client'; 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 { CarAddressSection } from './components/CarAddressSection'; import { CheckoutHeader } from './components/CheckoutHeader'; import { CouponSection } from './components/CouponSection'; import { PaymentSection } from './components/PaymentSection'; import { ShippingSection } from './components/ShippingSection'; import { SummarySection } from './components/SummarySection'; 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 { useGetProfile } from '@/app/[name]/(Profile)/profile/hooks/userProfileData'; import { useCheckoutStore } from '../store/Store'; @@ -17,28 +18,34 @@ import { useCheckoutStore } from '../store/Store'; function OrderDetailInex() { const { isSuccess } = useGetProfile(); const { data: cartItems } = useGetCartItems(isSuccess); - const [deliveryType, setDeliveryType] = React.useState('0'); - const [paymentType, setPaymentType] = React.useState('0'); + const { state: cartModal, toggle: toggleCartModal } = useToggle(); + const { data: shipmentMethod } = useGetShipmentMethod(); + const { + deliveryType, + setDeliveryType, + paymentType, + setPaymentType, + tableNumber, + setTableNumber, + setSelectedAddressId, + setIsSelectedAddress, + setIsSelectedPayment, + setIsSelectedShipment, + } = useCheckoutStore(); const [couponType, setCouponType] = React.useState('0'); const [couponCode, setCouponCode] = React.useState(''); const [couponCodeError, setCouponCodeError] = React.useState(''); - 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 decrementTableNumber = () => setTableNumber((prev) => prev - 1); + const incrementTableNumber = () => setTableNumber(tableNumber + 1); + const decrementTableNumber = () => setTableNumber(Math.max(0, tableNumber - 1)); const changeDeliveryType = useCallback((id: string) => { setDeliveryType(id); - }, []); + }, [setDeliveryType]); const changePaymentType = useCallback((id: string) => { setPaymentType(id); - }, []); + }, [setPaymentType]); const changeCouponType = useCallback((id: string) => { setCouponCode(''); @@ -53,31 +60,24 @@ function OrderDetailInex() { useEffect(() => { if (cartItems?.data?.deliveryMethodId) { setDeliveryType(cartItems.data.deliveryMethodId); + setIsSelectedShipment(true); } - }, [cartItems?.data?.deliveryMethodId]); + }, [cartItems?.data?.deliveryMethodId, setDeliveryType, setIsSelectedShipment]); useEffect(() => { if (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(() => { if (cartItems?.data?.addressId) { const addressId = cartItems.data.addressId; - setAddressCart(addressId, { - onSuccess: () => { - setIsSelectedAddress(true); - setSelectedAddressId(addressId ?? null); - }, - }); + setIsSelectedAddress(true); + setSelectedAddressId(addressId ?? null); } - }, [cartItems?.data?.addressId, setAddressCart, setIsSelectedAddress, setSelectedAddressId]); + }, [cartItems?.data?.addressId, setIsSelectedAddress, setSelectedAddressId]); useEffect(() => { if (cartItems?.data?.coupon?.couponCode && cartItems.data.couponDiscount > 0) { @@ -104,6 +104,10 @@ function OrderDetailInex() { onDeliveryTypeChange={changeDeliveryType} /> + {selectedDeliveryMethod?.method === 'deliveryCar' && ( + + )} + {shouldShowAddress && ( )} diff --git a/src/app/[name]/(Dialogs)/order/checkout/service/OrderService.ts b/src/app/[name]/(Dialogs)/order/checkout/service/OrderService.ts index ffef0d9..45f7817 100644 --- a/src/app/[name]/(Dialogs)/order/checkout/service/OrderService.ts +++ b/src/app/[name]/(Dialogs)/order/checkout/service/OrderService.ts @@ -39,8 +39,16 @@ export const setPaymentMethod = async (id: string) => { return data; }; -export const createOrder = async (): Promise => { - const { data } = await api.post("/public/checkout"); +export const createOrder = async (orderData?: { + deliveryMethodId?: string; + paymentMethodId?: string; + addressId?: string; + tableNumber?: number; +}): Promise => { + const { data } = await api.post( + "/public/checkout", + orderData + ); return data; }; diff --git a/src/app/[name]/(Dialogs)/order/checkout/store/Store.ts b/src/app/[name]/(Dialogs)/order/checkout/store/Store.ts index 5435105..dd2b768 100644 --- a/src/app/[name]/(Dialogs)/order/checkout/store/Store.ts +++ b/src/app/[name]/(Dialogs)/order/checkout/store/Store.ts @@ -1,13 +1,30 @@ import { create } from "zustand"; +import { createJSONStorage, persist } from "zustand/middleware"; import { CheckoutStoreType } from "../types/Types"; -export const useCheckoutStore = create((set) => ({ - isSelectedAddress: false, - setIsSelectedAddress: (value) => set({ isSelectedAddress: value }), - selectedAddressId: null, - setSelectedAddressId: (value) => set({ selectedAddressId: value }), - isSelectedPayment: false, - setIsSelectedPayment: (value) => set({ isSelectedPayment: value }), - isSelectedShipment: false, - setIsSelectedShipment: (value) => set({ isSelectedShipment: value }), -})); +export const useCheckoutStore = create()( + persist( + (set) => ({ + isSelectedAddress: false, + setIsSelectedAddress: (value) => set({ isSelectedAddress: value }), + selectedAddressId: null, + setSelectedAddressId: (value) => set({ selectedAddressId: value }), + isSelectedPayment: false, + setIsSelectedPayment: (value) => set({ isSelectedPayment: value }), + isSelectedShipment: false, + 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), + } + ) +); diff --git a/src/app/[name]/(Dialogs)/order/checkout/types/Types.ts b/src/app/[name]/(Dialogs)/order/checkout/types/Types.ts index 45a5bf7..2cd155f 100644 --- a/src/app/[name]/(Dialogs)/order/checkout/types/Types.ts +++ b/src/app/[name]/(Dialogs)/order/checkout/types/Types.ts @@ -127,6 +127,24 @@ export type CheckoutStoreType = { setIsSelectedPayment: (value: boolean) => void; isSelectedShipment: boolean; 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 {