Files
shop-front/src/app/cart/shipping/page.tsx
T
hamid zarghami e50206bca4 remove some logs
2025-11-06 10:04:45 +03:30

232 lines
9.9 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import CartSummary from '@/components/CartSummary'
import Layout from '@/hoc/Layout'
import { NextPage } from 'next'
// import CartItem from '../components/CartItem'
import TitleBack from '../components/TitleBack'
import ShippingMethodSelector from '../components/ShippingMethodSelector'
import { Location } from 'iconsax-react'
import { useGetCart, useSaveShipmentCart, useShippingCost } from '../hooks/useCartData'
// import { CartItemType } from '../types/Types'
import { useGetProfile } from '@/app/profile/hooks/useProfileData'
import Link from 'next/link'
import { useState, useEffect } from 'react'
import { toast } from '@/components/Toast'
import { extractErrorMessage } from '@/helpers/errorUtils'
const CartShipping: NextPage = () => {
const { data: cartData, isLoading: cartLoading, error: cartError } = useGetCart()
const { data: shippingData, isLoading: shippingLoading, error: shippingError } = useShippingCost()
const { data: profileData, isLoading: profileLoading, error: profileError } = useGetProfile()
const { mutate: saveShipmentCart } = useSaveShipmentCart()
// State برای ذخیره انتخاب‌های روش ارسال
const [selectedShipments, setSelectedShipments] = useState<Record<string, number>>({})
const [isSavingShipment, setIsSavingShipment] = useState(false)
// بارگذاری انتخاب‌های قبلی از localStorage
useEffect(() => {
const savedShipments = localStorage.getItem('selectedShipments')
if (savedShipments) {
setSelectedShipments(JSON.parse(savedShipments))
}
}, [])
// ذخیره انتخاب‌ها در localStorage
useEffect(() => {
if (Object.keys(selectedShipments).length > 0) {
localStorage.setItem('selectedShipments', JSON.stringify(selectedShipments))
}
}, [selectedShipments])
// پاک کردن انتخاب‌های نامعتبر وقتی shippingData تغییر می‌کند
useEffect(() => {
if (shippingData?.results?.shipping) {
const validShopIds = new Set(shippingData.results.shipping.map(shop => shop.shopId))
const filteredShipments = Object.fromEntries(
Object.entries(selectedShipments).filter(([shopId]) => validShopIds.has(shopId))
)
if (Object.keys(filteredShipments).length !== Object.keys(selectedShipments).length) {
setSelectedShipments(filteredShipments)
}
}
}, [shippingData, selectedShipments])
// هندلر انتخاب روش ارسال
const handleShipmentSelect = (shopId: string, shipperId: number) => {
setSelectedShipments(prev => ({
...prev,
[shopId]: shipperId
}))
}
// چک کردن اینکه آیا همه فروشگاه‌ها روش ارسال انتخاب کرده‌اند
const allShipmentsSelected = shippingData?.results?.shipping?.every(shop =>
selectedShipments[shop.shopId] !== undefined
) || false
// هندلر پاک کردن همه انتخاب‌ها
const handleClearSelections = () => {
setSelectedShipments({})
localStorage.removeItem('selectedShipments')
}
// هندلر ذخیره انتخاب‌های ارسال و انتقال به صفحه پرداخت
const handleProceedToPayment = async () => {
if (!allShipmentsSelected) return
setIsSavingShipment(true)
// فیلتر کردن selectedShipments تا فقط shop هایی که در shippingData وجود دارند
const validShopIds = new Set(shippingData?.results?.shipping?.map(shop => shop.shopId) || [])
// تبدیل selectedShipments به فرمت مورد نیاز API
const shipmentsInfo = Object.entries(selectedShipments)
.filter(([shopId]) => validShopIds.has(shopId))
.map(([shopId, shipperId]) => ({
shopId,
shipmentId: shipperId
}))
// ذخیره انتخاب‌ها در API
await new Promise<void>((resolve, reject) => {
saveShipmentCart({ shipmentsInfo }, {
onSuccess: () => {
resolve()
window.location.href = '/cart/payment'
},
onError: (error) => {
setIsSavingShipment(false)
toast(extractErrorMessage(error))
reject(error)
}
})
})
}
if (cartLoading || shippingLoading || profileLoading) {
return (
<div className="mt-14 px-4 sm:px-6 lg:px-20">
<div className="flex items-center justify-center h-64">
<div className="text-lg">در حال بارگذاری...</div>
</div>
</div>
)
}
if (cartError || shippingError || profileError) {
return (
<div className="mt-14 px-4 sm:px-6 lg:px-20">
<div className="flex items-center justify-center h-64">
<div className="text-lg text-red-500">خطا در بارگذاری اطلاعات</div>
</div>
</div>
)
}
const cart = cartData?.results?.cart
const items = cart?.items || []
const profile = profileData?.results?.info
if (!items.length) {
return (
<div className="mt-14 px-4 sm:px-6 lg:px-20">
<div className="flex items-center justify-center h-64">
<div className="text-lg">سبد خرید شما خالی است</div>
</div>
</div>
)
}
// محاسبه هزینه ارسال بر اساس انتخاب‌های کاربر
const totalShippingCost = shippingData?.results?.shipping?.reduce((total, shop) => {
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
// محاسبه قیمت نهایی
const finalTotal = (cart?.payable_price || 0) + totalShippingCost
return (
<div className="mt-14 px-4 sm:px-6 lg:px-20">
<div className="mt-6 flex flex-col lg:flex-row gap-6">
<div className='flex-1'>
<TitleBack title='آدرس و تایید جزئیات' />
<div className='mt-5 border border-border rounded-2xl p-4 sm:p-6 flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4'>
<div className='flex gap-2 items-start sm:items-center'>
<Location size={20} color='#333333' className='min-w-5 mt-1 sm:mt-0' />
<div className='text-xs text-[#7F7F7F]'>
<div>
آدرس تحویل سفارش
</div>
{profile?.userAddress && (
<div className='mt-2 text-sm text-black'>
{profile.userAddress.address}
{profile.userAddress.city && `، ${profile.userAddress.city.name}`}
{profile.userAddress.province && `، ${profile.userAddress.province.name}`}
</div>
)}
</div>
</div>
<Link href={'/profile'} className='text-primary text-sm self-end sm:self-auto'>ویرایش</Link>
</div>
<ShippingMethodSelector
shippingData={shippingData?.results?.shipping || []}
selectedShipments={selectedShipments}
onShipmentSelect={handleShipmentSelect}
onClearSelections={handleClearSelections}
/>
{/* <div className="flex-1 mt-5 border border-border p-4 sm:p-5 rounded-2xl">
{items.map((item: CartItemType, index: number) => {
if (!item || !item.product || !item.variant) {
return null
}
return (
<CartItem
key={`${item.product._id}-${item.variant._id}`}
item={item}
noBorder={index === 0}
/>
)
})}
</div> */}
</div>
<div className="w-full lg:w-[360px] lg:flex-shrink-0">
<CartSummary
itemsCount={cart?.items_count || 0}
itemsPrice={cart?.retail_price || 0}
discount={cart?.total_discount || 0}
shippingCost={totalShippingCost}
total={finalTotal}
onConfirm={handleProceedToPayment}
confirmLabel="پرداخت"
className="w-full"
confirmDisabled={!allShipmentsSelected}
isLoading={isSavingShipment}
/>
{!allShipmentsSelected && (
<div className="mt-2 text-sm text-red-600 text-center">
لطفا برای همه فروشگاهها روش ارسال انتخاب کنید
</div>
)}
</div>
</div>
</div>
)
}
export default function CartShippingWithLayout() {
return (
<Layout>
<CartShipping />
</Layout>
)
}