diff --git a/src/app/cart/components/ShippingMethodSelector.tsx b/src/app/cart/components/ShippingMethodSelector.tsx index 4796e7d..1b74380 100644 --- a/src/app/cart/components/ShippingMethodSelector.tsx +++ b/src/app/cart/components/ShippingMethodSelector.tsx @@ -273,6 +273,11 @@ const ShippingMethodSelector = ({ ارزان‌ترین )} + {shipper.payDeliveryFeeOnDelivery && ( + + پرداخت در محل + + )}
زمان ارسال: {shipper.shippingDaysRange?.join(' تا ') || 'نامشخص'} @@ -282,14 +287,24 @@ const ShippingMethodSelector = ({
- {shipper.totalShippingCost.toLocaleString('fa-IR')} تومان - {priceDifference > 0 && ( -
- +{priceDifference.toLocaleString('fa-IR')} تومان -
+ {shipper.payDeliveryFeeOnDelivery ? ( + + {shipper.totalShippingCost.toLocaleString('fa-IR')} تومان در محل + + ) : ( + <> + {shipper.totalShippingCost.toLocaleString('fa-IR')} تومان + {priceDifference > 0 && ( +
+ +{priceDifference.toLocaleString('fa-IR')} تومان +
+ )} + )}
- هزینه ارسال کل این فروشگاه + {shipper.payDeliveryFeeOnDelivery + ? 'هزینه ارسال هنگام تحویل پرداخت می‌شود' + : 'هزینه ارسال کل این فروشگاه'}
diff --git a/src/app/cart/payment/page.tsx b/src/app/cart/payment/page.tsx index 74adcb2..87ec625 100644 --- a/src/app/cart/payment/page.tsx +++ b/src/app/cart/payment/page.tsx @@ -6,6 +6,7 @@ import TitleBack from '../components/TitleBack' import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group" import DiscountCard from '../components/DiscountCard' import { usePaymentMethods, useGetCart, useShippingCost, useCheckoutCart } from '../hooks/useCartData' +import { ShopShippingType } from '../types/Types' import { useState } from 'react' import { toast } from '@/components/Toast' import { useGetProfile } from '@/app/profile/hooks/useProfileData' @@ -50,12 +51,24 @@ const CartPayment: NextPage = () => { const savedShipments = typeof window !== 'undefined' ? localStorage.getItem('selectedShipments') : null const selectedShipments = savedShipments ? JSON.parse(savedShipments) : {} - // محاسبه هزینه ارسال بر اساس انتخاب‌های کاربر - const totalShippingCost = shippingData?.results?.shipping?.reduce((total, shop) => { + const getSelectedShipper = (shop: ShopShippingType) => { const selectedShipperId = selectedShipments[shop.shopId] - const selectedShipper = shop.shippers?.find(shipper => shipper.shipperId === selectedShipperId) - return total + (selectedShipper?.totalShippingCost || shop.shippers?.[0]?.totalShippingCost || 0) - }, 0) || 0 + return shop.shippers?.find(shipper => shipper.shipperId === selectedShipperId) || shop.shippers?.[0] + } + + const shippingTotals = shippingData?.results?.shipping?.reduce((totals, shop) => { + const shipper = getSelectedShipper(shop) + if (!shipper) return totals + if (shipper.payDeliveryFeeOnDelivery) { + totals.onDelivery += shipper.totalShippingCost + } else { + totals.online += shipper.totalShippingCost + } + return totals + }, { online: 0, onDelivery: 0 }) || { online: 0, onDelivery: 0 } + + const totalShippingCost = shippingTotals.online + const shippingCostOnDelivery = shippingTotals.onDelivery // محاسبه قیمت نهایی const finalTotal = (cart?.payable_price || 0) + totalShippingCost @@ -132,6 +145,7 @@ const CartPayment: NextPage = () => { itemsPrice={cart?.retail_price || 0} discount={cart.total_discount} shippingCost={totalShippingCost} + shippingCostOnDelivery={shippingCostOnDelivery} total={finalTotal} onConfirm={handlePayment} confirmLabel="پرداخت" diff --git a/src/app/cart/shipping/page.tsx b/src/app/cart/shipping/page.tsx index 03a2541..9f532ec 100644 --- a/src/app/cart/shipping/page.tsx +++ b/src/app/cart/shipping/page.tsx @@ -7,6 +7,7 @@ import TitleBack from '../components/TitleBack' import ShippingMethodSelector from '../components/ShippingMethodSelector' import { Location } from 'iconsax-react' import { useGetCart, useSaveShipmentCart, useShippingCost } from '../hooks/useCartData' +import { ShopShippingType } from '../types/Types' // import { CartItemType } from '../types/Types' import { useGetProfile } from '@/app/profile/hooks/useProfileData' import Link from 'next/link' @@ -143,11 +144,24 @@ const CartShipping: NextPage = () => { } // محاسبه هزینه ارسال بر اساس انتخاب‌های کاربر - const totalShippingCost = shippingData?.results?.shipping?.reduce((total, shop) => { + const getSelectedShipper = (shop: ShopShippingType) => { const selectedShipperId = selectedShipments[shop.shopId] - const selectedShipper = shop.shippers?.find(shipper => shipper.shipperId === selectedShipperId) - return total + (selectedShipper?.totalShippingCost || shop.shippers?.[0]?.totalShippingCost || 0) - }, 0) || 0 + return shop.shippers?.find(shipper => shipper.shipperId === selectedShipperId) || shop.shippers?.[0] + } + + const shippingTotals = shippingData?.results?.shipping?.reduce((totals, shop) => { + const shipper = getSelectedShipper(shop) + if (!shipper) return totals + if (shipper.payDeliveryFeeOnDelivery) { + totals.onDelivery += shipper.totalShippingCost + } else { + totals.online += shipper.totalShippingCost + } + return totals + }, { online: 0, onDelivery: 0 }) || { online: 0, onDelivery: 0 } + + const totalShippingCost = shippingTotals.online + const shippingCostOnDelivery = shippingTotals.onDelivery // محاسبه قیمت نهایی const finalTotal = (cart?.payable_price || 0) + totalShippingCost @@ -205,6 +219,7 @@ const CartShipping: NextPage = () => { itemsPrice={cart?.retail_price || 0} discount={cart?.total_discount || 0} shippingCost={totalShippingCost} + shippingCostOnDelivery={shippingCostOnDelivery} total={finalTotal} onConfirm={handleProceedToPayment} confirmLabel="پرداخت" diff --git a/src/app/cart/types/Types.ts b/src/app/cart/types/Types.ts index fccff57..1f04fc4 100644 --- a/src/app/cart/types/Types.ts +++ b/src/app/cart/types/Types.ts @@ -60,6 +60,7 @@ export type CartItemType = { description: string; deliveryTime: number; deliveryType: string; + payDeliveryFeeOnDelivery?: boolean; }>; warranty: { _id: number; @@ -224,6 +225,7 @@ export type ShipperType = { shipperName: string; shippingDaysRange: string[]; totalShippingCost: number; + payDeliveryFeeOnDelivery: boolean; items: ShippingItemType[]; }; diff --git a/src/app/profile/orders/[id]/invoice/page.tsx b/src/app/profile/orders/[id]/invoice/page.tsx index e36b003..e206b70 100644 --- a/src/app/profile/orders/[id]/invoice/page.tsx +++ b/src/app/profile/orders/[id]/invoice/page.tsx @@ -42,6 +42,7 @@ const OrderInvoicePage = () => { const totalDiscount = order.payment.priceDetails.total_discount const couponDiscount = order.payment.priceDetails.coupon_discount const shippingCost = order.payment.priceDetails.shipping_cost + const shippingCostOnDelivery = order.payment.priceDetails.shipping_cost_on_delivery || 0 const totalPrice = order.payment.totalPrice return ( @@ -212,6 +213,12 @@ const OrderInvoicePage = () => { هزینه ارسال: {NumberFormat(shippingCost)} تومان
+ {shippingCostOnDelivery > 0 && ( +
+ هزینه ارسال (پرداخت در محل): + {NumberFormat(shippingCostOnDelivery)} تومان +
+ )}
جمع کل: diff --git a/src/app/profile/orders/types/Types.ts b/src/app/profile/orders/types/Types.ts index 86cdd9b..d402b7f 100644 --- a/src/app/profile/orders/types/Types.ts +++ b/src/app/profile/orders/types/Types.ts @@ -94,6 +94,7 @@ export interface PaymentMethod { export interface PriceDetails { shipping_cost: number; + shipping_cost_on_delivery?: number; process_cost: number; total_retail_price: number; total_payable_price: number; diff --git a/src/components/CartSummary.tsx b/src/components/CartSummary.tsx index 7c99336..97456c6 100644 --- a/src/components/CartSummary.tsx +++ b/src/components/CartSummary.tsx @@ -10,6 +10,7 @@ type CartSummaryProps = { itemsPrice: number; discount: number; shippingCost?: number; + shippingCostOnDelivery?: number; total: number; onConfirm?: () => void; confirmHref?: string; @@ -34,7 +35,7 @@ const Row: FC<{ label: string; value: string | number; emphasize?: boolean }> = }; const CartSummary: FC = (props) => { - const { itemsCount, itemsPrice, discount, shippingCost, total, onConfirm, onDownloadInvoice, className, confirmHref, confirmLabel, confirmDisabled, isLoading } = props; + const { itemsCount, itemsPrice, discount, shippingCost, shippingCostOnDelivery, total, onConfirm, onDownloadInvoice, className, confirmHref, confirmLabel, confirmDisabled, isLoading } = props; return (
@@ -49,6 +50,9 @@ const CartSummary: FC = (props) => { {shippingCost !== undefined && shippingCost > 0 && ( )} + {shippingCostOnDelivery !== undefined && shippingCostOnDelivery > 0 && ( + + )}
diff --git a/src/components/Input.tsx b/src/components/Input.tsx index 294321d..9543ef2 100644 --- a/src/components/Input.tsx +++ b/src/components/Input.tsx @@ -68,11 +68,17 @@ const Input: FC = (props: Props) => { } }, [props.value]) + useEffect(() => { + if (props.variant === 'search') { + setSearch(String(props.value ?? '')) + } + }, [props.value, props.variant]) + useEffect(() => { if (props.variant === 'search' && props.onChangeSearchFinal) { const timeout = setTimeout(() => { props.onChangeSearchFinal?.(search) - }, 1000) + }, 500) return () => clearTimeout(timeout) } }, [search, props]) diff --git a/src/share/components/DesktopSearch.tsx b/src/share/components/DesktopSearch.tsx index bf7820c..83fa069 100644 --- a/src/share/components/DesktopSearch.tsx +++ b/src/share/components/DesktopSearch.tsx @@ -7,6 +7,7 @@ import Image from 'next/image' import { createPortal } from 'react-dom' const DesktopSearch: FC = () => { + const [inputValue, setInputValue] = useState('') const [searchQuery, setSearchQuery] = useState('') const [isOpen, setIsOpen] = useState(false) const [mounted, setMounted] = useState(false) @@ -16,13 +17,14 @@ const DesktopSearch: FC = () => { const [dropdownPosition, setDropdownPosition] = useState({ top: 0, left: 0, width: 0 }) const { data: searchResults, isLoading } = useProductSearch(searchQuery) + const isSearching = inputValue.length > 0 && (isLoading || inputValue !== searchQuery) useEffect(() => { setMounted(true) }, []) - const handleSearch = (value: string) => { - setSearchQuery(value) + const handleInputChange = (value: string) => { + setInputValue(value) setIsOpen(value.length > 0) if (value.length > 0 && inputRef.current) { @@ -37,6 +39,7 @@ const DesktopSearch: FC = () => { const handleProductClick = (url: string) => { router.push(url) + setInputValue('') setSearchQuery('') setIsOpen(false) } @@ -79,12 +82,13 @@ const DesktopSearch: FC = () => { className='w-full' variant='search' placeholder='جستجو' - value={searchQuery} - onChange={(e) => handleSearch(e.target.value)} + value={inputValue} + onChange={(e) => handleInputChange(e.target.value)} + onChangeSearchFinal={setSearchQuery} />
- {mounted && isOpen && searchQuery.length > 0 && createPortal( + {mounted && isOpen && inputValue.length > 0 && createPortal(
{ width: `${dropdownPosition.width}px` }} > - {isLoading ? ( + {isSearching ? (
در حال جستجو...
diff --git a/src/share/components/MobileSearch.tsx b/src/share/components/MobileSearch.tsx index 1f77399..6ea7cd8 100644 --- a/src/share/components/MobileSearch.tsx +++ b/src/share/components/MobileSearch.tsx @@ -8,17 +8,16 @@ import Image from 'next/image' const MobileSearch: FC = () => { const [isSearchOpen, setIsSearchOpen] = useState(false) + const [inputValue, setInputValue] = useState('') const [searchQuery, setSearchQuery] = useState('') const router = useRouter() const { data: searchResults, isLoading } = useProductSearch(searchQuery) - - const handleSearch = (value: string) => { - setSearchQuery(value) - } + const isSearching = inputValue.length > 0 && (isLoading || inputValue !== searchQuery) const handleClose = () => { setIsSearchOpen(false) + setInputValue('') setSearchQuery('') } @@ -36,8 +35,9 @@ const MobileSearch: FC = () => { variant='search' placeholder='جستجو' autoFocus - value={searchQuery} - onChange={(e) => handleSearch(e.target.value)} + value={inputValue} + onChange={(e) => setInputValue(e.target.value)} + onChangeSearchFinal={setSearchQuery} />
- {searchQuery.length > 0 && ( + {inputValue.length > 0 && ( <> - {isLoading ? ( + {isSearching ? (
در حال جستجو...