Files
parsshop/app/checkout/page.tsx
2026-04-27 14:23:07 +03:30

688 lines
45 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 { useCart } from "@/components/context/cartcontext";
import Link from "next/link";
import { useState, useEffect } from "react";
import {
ShoppingBag,
ChevronLeft,
ChevronRight,
Truck,
CreditCard,
MapPin,
User,
Lock
} from "lucide-react";
import PaymentMethodsSection from "@/components/PaymentMethods";
import { getCartApi } from "@/public/src/services/cart/api";
import { fetchUserAddresses, type Address, addAddressApi, NewAddressData, updateAddressApi, deleteAddressApi } from "@/public/src/services/address/api";
export default function CheckoutPage() {
const { cart } = useCart();
const [shippingMethod, setShippingMethod] = useState('post');
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [serverSummary, setServerSummary] = useState<any>(null);
const [addresses, setAddresses] = useState<Address[]>([]);
const [selectedAddressId, setSelectedAddressId] = useState<string | null>(null);
const [showNewAddressForm, setShowNewAddressForm] = useState(false);
const [isAddressLoading, setIsAddressLoading] = useState(true);
const [newAddress, setNewAddress] = useState<NewAddressData>({
title: 'خانه',
recipientName: '',
phone: '',
province: '',
city: '',
postalCode: '',
addressLine: '',
plaque: '',
unit: '',
isDefault: false
});
useEffect(() => {
const initializeCheckout = async () => {
// توجه: در صفحه Cart از refreshToken استفاده کرده بودید، اگر اینجا accessToken است دقت کنید که یکسان باشند
const token = localStorage.getItem('accessToken') || localStorage.getItem('refreshToken');
if (token) {
setIsAuthenticated(true);
// ۳. دریافت اطلاعات سبد خرید از سرور
try {
const data = await getCartApi();
if (data && data.summary) {
setServerSummary(data.summary);
}
} catch (error) {
console.error("خطا در دریافت اطلاعات سبد خرید:", error);
}
}
setIsLoading(false);
};
initializeCheckout();
}, []);
useEffect(() => {
const initializeCheckout = async () => {
const token = localStorage.getItem('accessToken') || localStorage.getItem('refreshToken');
if (token) {
setIsAuthenticated(true);
try {
// دریافت همزمان اطلاعات سبد و آدرس‌ها
const [cartData, addressData] = await Promise.all([
getCartApi(),
fetchUserAddresses()
]);
if (cartData && cartData.summary) {
setServerSummary(cartData.summary);
}
if (addressData && addressData.length > 0) {
setAddresses(addressData);
// انتخاب آدرس پیش‌فرض یا اولین آدرس به عنوان انتخاب‌شده
const defaultAddress = addressData.find(addr => addr.isDefault) || addressData[0];
setSelectedAddressId(defaultAddress.id);
} else {
// اگر آدرسی وجود نداشت، فرم افزودن آدرس را نمایش بده
setShowNewAddressForm(true);
}
} catch (error) {
console.error("خطا در دریافت اطلاعات صفحه پرداخت:", error);
} finally {
setIsAddressLoading(false);
}
} else {
setIsAuthenticated(false);
setIsAddressLoading(false);
}
setIsLoading(false);
};
initializeCheckout();
}, []);
const handleAddressInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {
const { name, value } = e.target;
setNewAddress(prev => ({ ...prev, [name]: value }));
};
const handleAddNewAddress = async (e: React.FormEvent) => {
e.preventDefault();
// اینجا می‌توانید ولیدیشن‌های لازم را اضافه کنید
try {
const addedAddress = await addAddressApi(newAddress);
// آدرس جدید را به لیست اضافه کن و آن را به عنوان انتخاب شده قرار بده
setAddresses(prev => [...prev, addedAddress]);
setSelectedAddressId(addedAddress.id);
setShowNewAddressForm(false); // فرم را مخفی کن
// فرم را ریست کن
setNewAddress({
title: 'خانه', recipientName: '', phone: '', province: '', city: '',
postalCode: '', addressLine: '', plaque: '', unit: '', isDefault: false
});
} catch (error) {
console.error("خطا در ذخیره آدرس:", error);
// اینجا می‌توانید به کاربر خطا را نمایش دهید
}
};
const [editingAddressId, setEditingAddressId] = useState(null);
// 2. تابع کلیک روی دکمه ویرایش
const handleEditClick = (address: any, e: any) => {
e.preventDefault();
e.stopPropagation(); // برای جلوگیری از انتخاب شدن radio button هنگام کلیک روی ویرایش
setEditingAddressId(address.id);
// پر کردن مقادیر فرم با دیتای آدرس انتخاب شده (فرض بر این است که استیت شما setNewAddress نام دارد)
setNewAddress({
title: address.title || "",
recipientName: address.recipientName || "",
phone: address.phone || "",
province: address.province || "",
city: address.city || "",
postalCode: address.postalCode || "",
addressLine: address.addressLine || "",
plaque: address.plaque || "",
unit: address.unit || "",
isDefault: address.isDefault || false
});
setShowNewAddressForm(true);
};
// 3. تابع فراخوانی API ویرایش
const handleUpdateAddress = async () => {
// اضافه کردن این شرط برای جلوگیری از خطای تایپ و توقف اجرا در صورت null بودن ID
if (!editingAddressId) return;
try {
const response = await updateAddressApi(editingAddressId, newAddress);
if (response.success) {
// آپدیت کردن آدرس ویرایش شده در لیست آدرس‌ها
setAddresses(prevAddresses =>
prevAddresses.map(addr => addr.id === editingAddressId ? response.data : addr)
);
// خروج از حالت فرم و ریست کردن مقادیر
setShowNewAddressForm(false);
setEditingAddressId(null);
setNewAddress({
title: "", recipientName: "", phone: "", province: "", city: "", postalCode: "", addressLine: "", plaque: "", unit: "", isDefault: false
});
}
} catch (error) {
// مدیریت خطا (در صورت نیاز آلرت یا توست نمایش دهید)
console.error("خطا در به‌روزرسانی آدرس:", error);
}
};
// 4. تابع انصراف یکپارچه شده
const handleCancelForm = () => {
setShowNewAddressForm(false);
setEditingAddressId(null);
setNewAddress({
title: "", recipientName: "", phone: "", province: "", city: "", postalCode: "", addressLine: "", plaque: "", unit: "", isDefault: false
});
};
const handleDeleteAddress = async (addressId: string, e: React.MouseEvent) => {
e.stopPropagation(); // جلوگیری از انتخاب شدن آدرس هنگام کلیک روی دکمه حذف
// گرفتن تاییدیه از کاربر قبل از حذف
const confirmDelete = window.confirm("آیا از حذف این آدرس اطمینان دارید؟");
if (!confirmDelete) return;
try {
const response = await deleteAddressApi(addressId);
if (response.success) {
// حذف آدرس از لیست موجود در State
setAddresses(prevAddresses =>
prevAddresses.filter(addr => addr.id !== addressId)
);
// اگر آدرسی که پاک شد همان آدرس انتخاب‌شده بود، انتخاب را لغو کن
if (selectedAddressId === addressId) {
setSelectedAddressId(null);
}
// اگر آدرسی که پاک شد در حال ویرایش بود، فرم ویرایش را ببند
if (editingAddressId === addressId) {
setShowNewAddressForm(false);
setEditingAddressId(null);
setNewAddress({
title: "", recipientName: "", phone: "", province: "", city: "", postalCode: "", addressLine: "", plaque: "", unit: "", isDefault: false
});
}
}
} catch (error) {
console.error("خطا در حذف آدرس:", error);
// اینجا می‌توانید یک Toast یا Alert برای نمایش خطا به کاربر اضافه کنید
}
};
// محاسبه قیمت کل و تعداد
const parsePrice = (priceStr?: number | null | string) => {
if (!priceStr) return 0;
return Number(priceStr.toString().replace(/,/g, ''));
};
// ۴. استفاده از اطلاعات سرور در صورت لاگین بودن، در غیر این صورت استفاده از Context
const totalPrice = isAuthenticated && serverSummary
? serverSummary.totalPrice || serverSummary.total || 0
: cart.reduce((total, item) => total + (parsePrice(item.price) * item.quantity), 0);
const totalItems = isAuthenticated && serverSummary
? serverSummary.totalQuantity || serverSummary.itemsCount || 0
: cart.reduce((total, item) => total + item.quantity, 0);
const shippingCost = shippingMethod === 'post' ? 45000 : 75000;
const finalPrice = totalPrice + shippingCost;
// حالت در حال بررسی توکن
if (isLoading) {
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50/30">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-[#ffb900]"></div>
</div>
);
}
// اگر کاربر لاگین نبود
if (!isAuthenticated) {
return (
<div className="min-h-screen bg-gray-50/30 flex flex-col items-center justify-center p-6" dir="rtl">
<div className="bg-white p-12 rounded-[2rem] shadow-sm border border-gray-100 flex flex-col items-center max-w-md w-full text-center">
<div className="bg-gray-100 w-24 h-24 rounded-full flex items-center justify-center mb-6">
<Lock size={40} className="text-gray-400" />
</div>
<h2 className="text-xl font-bold text-gray-800 mb-3">دسترسی محدود</h2>
<p className="text-gray-500 mb-8 leading-relaxed text-sm">
برای ثبت نهایی سفارش و مشاهده این صفحه، باید ابتدا وارد حساب کاربری خود شوید یا ثبتنام کنید.
</p>
<Link href="/cart" className="w-full bg-[#ffb900] hover:bg-[#e5a600] text-[#1A2332] font-bold py-3 rounded-xl transition-all flex items-center justify-center gap-2">
<ChevronRight size={18} />
بازگشت به سبد خرید
</Link>
</div>
</div>
);
}
// رندر اصلی کامپوننت Checkout
return (
<main className="bg-gray-50/30 min-h-screen pb-20" dir="rtl">
<div className="container mx-auto px-4 py-8 max-w-6xl">
<div className="mb-10">
<div className="flex items-center justify-between mb-8">
<h1 className="text-xl md:text-3xl font-black text-[#1A2332]">
اطلاعات ارسال
</h1>
<Link href="/cart" className="text-sm text-gray-500 hover:text-[#1A2332] flex items-center gap-1 transition-colors">
<ChevronRight size={16} />
بازگشت به سبد خرید
</Link>
</div>
<div className="relative w-full max-w-2xl mx-auto px-2 sm:px-0 mb-12">
<div className="absolute top-[20px] sm:top-[24px] left-[16.5%] right-[16.5%] h-[2px] bg-gray-200 z-0">
<div className="h-full bg-[#ffb900] w-[50%] transition-all duration-500 ease-in-out"></div>
</div>
<div className="flex justify-between relative z-10">
<Link href="/cart" className="flex flex-col items-center w-1/3 group cursor-pointer">
<div className="w-10 h-10 sm:w-12 sm:h-12 bg-[#ffb900] text-[#1A2332] rounded-full flex items-center justify-center shadow-md mb-2 sm:mb-3 ring-[6px] ring-[#f8fafc] sm:ring-[#f8fafc] transition-transform group-hover:scale-110">
<ShoppingBag className="w-5 h-5 sm:w-6 sm:h-6" strokeWidth={2} />
</div>
<span className="text-[10px] sm:text-sm font-bold text-[#1A2332] text-center">سبد خرید</span>
</Link>
<div className="flex flex-col items-center w-1/3">
<div className="w-10 h-10 sm:w-12 sm:h-12 bg-[#ffb900] text-[#1A2332] rounded-full flex items-center justify-center shadow-[0_0_15px_rgba(255,185,0,0.4)] mb-2 sm:mb-3 ring-[6px] ring-[#ffb900]/20 transition-all">
<Truck className="w-4 h-4 sm:w-5 sm:h-5" strokeWidth={2} />
</div>
<span className="text-[10px] sm:text-sm font-bold text-[#1A2332] text-center">اطلاعات ارسال</span>
</div>
<div className="flex flex-col items-center w-1/3">
<div className="w-10 h-10 sm:w-12 sm:h-12 bg-white border-2 border-gray-200 text-gray-400 rounded-full flex items-center justify-center mb-2 sm:mb-3 ring-[6px] ring-[#f8fafc] sm:ring-[#f8fafc]">
<CreditCard className="w-4 h-4 sm:w-5 sm:h-5" />
</div>
<span className="text-[10px] sm:text-sm font-medium text-gray-400 text-center">پرداخت</span>
</div>
</div>
</div>
</div>
<div className="flex flex-col lg:flex-row gap-6 lg:gap-8">
{/* ... (فرم‌های آدرس گیرنده بدون تغییر) ... */}
<div className="flex-1 space-y-6">
<div className="flex-1 space-y-6">
{isAddressLoading ? (
<div className="bg-white rounded-[1rem] p-8 shadow-sm flex justify-center items-center">
<p className="text-gray-500">در حال بارگذاری آدرسها...</p>
</div>
) : (
<>
{showNewAddressForm ? (
<div className="bg-white rounded-[1rem] p-6 shadow-sm space-y-6 border border-gray-100">
<div className="flex justify-between items-center border-b pb-4">
<button className="text-lg cursor-pointer font-bold text-gray-800">
{editingAddressId ? 'ویرایش آدرس' : 'افزودن آدرس جدید'}
</button>
{addresses.length > 0 && (
<button
type="button"
onClick={handleCancelForm}
className="text-sm cursor-pointer text-red-500 hover:text-red-700"
>
انصراف
</button>
)}
</div>
<div className="bg-[#FBFBFB] border border-gray-200 rounded-2xl p-8 shadow-sm space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<label className="text-sm text-gray-600 font-medium">
عنوان آدرس (مثلاً: خانه، محل کار)
</label>
<input
type="text"
name="title"
value={newAddress.title}
onChange={handleAddressInputChange}
className="w-full border border-gray-300 rounded-lg p-3 text-sm bg-white text-gray-800 focus:outline-none focus:border-[#FFB900] focus:ring-1 focus:ring-[#FFB900] transition-all placeholder-gray-400"
placeholder="خانه"
/>
</div>
<div className="space-y-2">
<label className="text-sm text-gray-600 font-medium">
نام و نام خانوادگی گیرنده
</label>
<input
type="text"
name="recipientName"
value={newAddress.recipientName}
onChange={handleAddressInputChange}
className="w-full border border-gray-300 rounded-lg p-3 text-sm bg-white text-gray-800 focus:outline-none focus:border-[#FFB900] focus:ring-1 focus:ring-[#FFB900] transition-all placeholder-gray-400"
placeholder="نام گیرنده"
/>
</div>
<div className="space-y-2">
<label className="text-sm text-gray-600 font-medium">شماره موبایل</label>
<input
type="tel"
name="phone"
value={newAddress.phone}
onChange={handleAddressInputChange}
className="w-full border border-gray-300 rounded-lg p-3 text-sm bg-white text-gray-800 focus:outline-none focus:border-[#FFB900] focus:ring-1 focus:ring-[#FFB900] transition-all placeholder-gray-400"
placeholder="09123456789"
/>
</div>
<div className="space-y-2">
<label className="text-sm text-gray-600 font-medium">استان</label>
<input
type="text"
name="province"
value={newAddress.province}
onChange={handleAddressInputChange}
className="w-full border border-gray-300 rounded-lg p-3 text-sm bg-white text-gray-800 focus:outline-none focus:border-[#FFB900] focus:ring-1 focus:ring-[#FFB900] transition-all placeholder-gray-400"
placeholder="تهران"
/>
</div>
<div className="space-y-2">
<label className="text-sm text-gray-600 font-medium">شهر</label>
<input
type="text"
name="city"
value={newAddress.city}
onChange={handleAddressInputChange}
className="w-full border border-gray-300 rounded-lg p-3 text-sm bg-white text-gray-800 focus:outline-none focus:border-[#FFB900] focus:ring-1 focus:ring-[#FFB900] transition-all placeholder-gray-400"
placeholder="تهران"
/>
</div>
<div className="space-y-2">
<label className="text-sm text-gray-600 font-medium">
کد پستی (۱۰ رقمی)
</label>
<input
type="text"
name="postalCode"
value={newAddress.postalCode}
onChange={handleAddressInputChange}
className="w-full border border-gray-300 rounded-lg p-3 text-sm bg-white text-gray-800 focus:outline-none focus:border-[#FFB900] focus:ring-1 focus:ring-[#FFB900] transition-all placeholder-gray-400"
placeholder="1234567890"
/>
</div>
</div>
<div className="space-y-2">
<label className="text-sm text-gray-600 font-medium">آدرس دقیق پستی</label>
<textarea
name="addressLine"
value={newAddress.addressLine}
onChange={handleAddressInputChange}
rows={3}
className="w-full border border-gray-300 rounded-lg p-3 text-sm bg-white text-gray-800 focus:outline-none focus:border-[#FFB900] focus:ring-1 focus:ring-[#FFB900] transition-all placeholder-gray-400"
placeholder="خیابان اصلی، کوچه فرعی..."
/>
</div>
<div className="grid grid-cols-2 gap-6 md:w-1/2">
<div className="space-y-2">
<label className="text-sm text-gray-600 font-medium">پلاک</label>
<input
type="text"
name="plaque"
value={newAddress.plaque}
onChange={handleAddressInputChange}
className="w-full border border-gray-300 rounded-lg p-3 text-sm bg-white text-gray-800 focus:outline-none focus:border-[#FFB900] focus:ring-1 focus:ring-[#FFB900] transition-all"
/>
</div>
<div className="space-y-2">
<label className="text-sm text-gray-600 font-medium">واحد (اختیاری)</label>
<input
type="text"
name="unit"
value={newAddress.unit}
onChange={handleAddressInputChange}
className="w-full border border-gray-300 rounded-lg p-3 text-sm bg-white text-gray-800 focus:outline-none focus:border-[#FFB900] focus:ring-1 focus:ring-[#FFB900] transition-all"
/>
</div>
</div>
<div className="pt-4">
<button
type="button"
onClick={editingAddressId ? handleUpdateAddress : handleAddNewAddress}
className="w-full cursor-pointer md:w-auto bg-[#FFB900] text-white px-10 py-3 rounded-lg font-semibold shadow-md hover:bg-[#e5a000] transition-colors"
>
{editingAddressId ? 'ویرایش و ذخیره آدرس' : 'ثبت و ذخیره آدرس'}
</button>
</div>
</div>
</div>
) : (
/* ================= بخش لیست آدرس‌های موجود ================= */
<div className="bg-white rounded-[1rem] p-6 shadow-sm space-y-4">
<div className="flex justify-between items-center border-b border-[#dcdbdb] pb-4 mb-4">
<h2 className="text-lg font-bold text-gray-800">انتخاب آدرس ارسال</h2>
<button
type="button"
onClick={() => {
setEditingAddressId(null);
setNewAddress({ title: "", recipientName: "", phone: "", province: "", city: "", postalCode: "", addressLine: "", plaque: "", unit: "", isDefault: false });
setShowNewAddressForm(true);
}}
className="text-sm cursor-pointer text-blue-600 hover:text-blue-800 font-medium flex items-center gap-1"
>
<span>+</span> افزودن آدرس جدید
</button>
</div>
{addresses.length === 0 ? (
<div className="text-center py-6 text-gray-500">
هیچ آدرسی یافت نشد. لطفاً یک آدرس جدید اضافه کنید.
</div>
) : (
<div className="space-y-3">
{addresses.map((address) => (
<label
key={address.id}
className={`relative flex flex-col gap-4 p-3 cursor-pointer rounded-2xl border transition-all duration-300 ${selectedAddressId === address.id
? 'border-[#ffb900] bg-[#ffb900]/[0.03] ring-1 ring-[#ffb900]/20 shadow-sm'
: 'border-gray-200 bg-white hover:border-gray-300 hover:shadow-sm'
}`}
>
<div className="flex items-start gap-4">
{/* رادیو باتن */}
<div className="pt-0.5 relative flex items-center justify-center">
<input
type="radio"
name="selectedAddress"
value={address.id}
checked={selectedAddressId === address.id}
onChange={() => setSelectedAddressId(address.id)}
// حذف استایل پیش‌فرض و اعمال بوردر و رنگ سفارشی
className="peer appearance-none w-[18px] h-[18px] border-[1.5px] border-gray-300 rounded-full checked:border-[#ffb900] checked:bg-[#ffb900] cursor-pointer transition-all focus:outline-none focus:ring-2 focus:ring-[#ffb900]/20 focus:ring-offset-1 bg-white"
/>
{/* دایره سفید مرکزی که فقط در حالت انتخاب شده نمایش داده می‌شود */}
<div className="pointer-events-none absolute w-[10px] h-[10px] rounded-full bg-white opacity-0 peer-checked:opacity-100 transition-opacity"></div>
</div>
<div className="flex-1 space-y-3">
{/* عنوان و متن آدرس */}
<div>
{address.title && (
<span className="inline-block mb-2 bg-gray-50 text-gray-500 border border-gray-200 text-[11px] font-medium px-2.5 py-0.5 rounded-full">
{address.title}
</span>
)}
<p className="font-medium text-gray-800 leading-relaxed text-sm md:text-base">
{address.addressLine}
</p>
</div>
{/* جزئیات آدرس (مینیمال شده) */}
<div className="flex flex-wrap items-center text-xs md:text-sm text-gray-500 gap-x-2 gap-y-1.5">
<span>{address.recipientName}</span>
<span className="text-gray-300 text-[10px]"></span>
<span dir="ltr">{address.phone}</span>
<span className="text-gray-300 text-[10px]"></span>
<span>کد پستی: {address.postalCode}</span>
<span className="text-gray-300 text-[10px]"></span>
<span>
پلاک {address.plaque}
{address.unit ? `، واحد ${address.unit}` : ''}
</span>
</div>
</div>
</div>
{/* نوار دکمه‌های عملیاتی */}
<div className="flex items-center justify-end gap-2 pt-3 mt-1 border-t border-gray-100/80">
<button
type="button"
onClick={(e) => handleEditClick(address, e)}
className="px-3 cursor-pointer py-1.5 text-xs font-medium text-gray-500 transition-colors rounded-lg hover:bg-blue-50 hover:text-blue-600 focus:outline-none"
>
ویرایش آدرس
</button>
<button
type="button"
onClick={(e) => handleDeleteAddress(address.id, e)}
className="px-3 cursor-pointer py-1.5 text-xs font-medium text-gray-500 transition-colors rounded-lg hover:bg-red-50 hover:text-red-600 focus:outline-none"
>
حذف
</button>
</div>
</label>
))}
</div>
)}
</div>
)}
</>
)}
<div className="bg-white rounded-[1rem] p-6 shadow-sm space-y-4">
<div className="flex items-center gap-3 mb-6 pb-4 ">
<div className="bg-[#1A2332]/5 p-2 rounded-lg text-[#1A2332]">
<Truck size={20} />
</div>
<h2 className="text-base md:text-lg font-bold text-[#1A2332]">نحوه ارسال</h2>
</div>
<div className="space-y-3">
<label className={`flex items-center justify-between p-4 rounded-xl border-1 cursor-pointer transition-all ${shippingMethod === 'post' ? 'border-[#ffb900] bg-[#ffb900]/3' : 'border-gray-100 hover:border-gray-200 bg-white'}`}>
<div className="flex items-center gap-3">
<div className={`w-5 h-5 rounded-full border-1 flex items-center justify-center ${shippingMethod === 'post' ? 'border-[#ffb900]' : 'border-gray-300'}`}>
{shippingMethod === 'post' && <div className="w-2.5 h-2.5 bg-[#ffb900] rounded-full" />}
</div>
<div>
<div className="font-bold text-[#1A2332]">پست پیشتاز</div>
<div className="text-xs text-gray-500 mt-1">زمان تحویل: ۳ تا ۵ روز کاری</div>
</div>
</div>
<div className="font-bold text-[#1A2332]">۴۵,۰۰۰ <span className="text-xs font-normal text-gray-500">تومان</span></div>
<input type="radio" name="shipping" value="post" className="hidden" checked={shippingMethod === 'post'} onChange={() => setShippingMethod('post')} />
</label>
<label className={`flex items-center justify-between p-4 rounded-xl border-1 cursor-pointer transition-all ${shippingMethod === 'tipax' ? 'border-[#ffb900] bg-[#ffb900]/3' : 'border-gray-100 hover:border-gray-200 bg-white'}`}>
<div className="flex items-center gap-3">
<div className={`w-5 h-5 rounded-full border-1 flex items-center justify-center ${shippingMethod === 'tipax' ? 'border-[#ffb900]' : 'border-gray-300'}`}>
{shippingMethod === 'tipax' && <div className="w-2.5 h-2.5 bg-[#ffb900] rounded-full" />}
</div>
<div>
<div className="font-bold text-[#1A2332]">تیپاکس (پسکرایه)</div>
<div className="text-xs text-gray-500 mt-1">زمان تحویل: ۱ تا ۲ روز کاری</div>
</div>
</div>
<div className="font-bold text-[#1A2332]">۷۵,۰۰۰ <span className="text-xs font-normal text-gray-500">تومان</span></div>
<input type="radio" name="shipping" value="tipax" className="hidden" checked={shippingMethod === 'tipax'} onChange={() => setShippingMethod('tipax')} />
</label>
</div>
</div>
</div>
</div>
<div className="w-full lg:w-[400px] shrink-0">
<div className="bg-white rounded-[1rem] p-6 md:p-8 shadow-sm sticky top-6">
<h2 className="text-lg md:text-xl font-bold text-[#1A2332] mb-6">خلاصه سفارش</h2>
<div className="space-y-4 mb-6">
<div className="flex justify-between items-center text-xs md:text-sm">
<span className="text-gray-500">مبلغ کالاها ({totalItems})</span>
<span className="font-bold text-[#1A2332]">{totalPrice > 0 ? totalPrice.toLocaleString('fa-IR') : '۰'} <span className="text-[10px] font-normal text-gray-500">تومان</span></span>
</div>
<div className="flex justify-between items-center text-xs md:text-sm">
<span className="text-gray-500">هزینه ارسال</span>
<span className="font-bold text-[#1A2332]">{shippingCost.toLocaleString('fa-IR')} <span className="text-[10px] font-normal text-gray-500">تومان</span></span>
</div>
</div>
{/* ... بقیه قسمت‌ها (متد ارسال و دکمه پرداخت) بدون تغییر ... */}
<div className="w-full border-t-2 border-dashed border-gray-100 my-6"></div>
<div className="w-full border-t-2 border-dashed border-gray-100 my-6"></div>
<div>
<PaymentMethodsSection />
<span className="font-black mt-4 mb-4 justify-center items-center flex gap-4 text-[#1A2332] tracking-tight">
<span className=" font-bold text-gray-600">مبلغ قابل پرداخت</span>
<span className="text-base flex items-center md:text-lg font-bold text-[#1A2332]">
{finalPrice > 0 && finalPrice.toLocaleString('fa-IR')}
{finalPrice > 0 && (
<span className="text-xs md:text-sm font-medium text-gray-500 mr-1">تومان</span>
)}
</span>
</span>
</div>
<Link href="/payment" className="w-full bg-[#ffb900] hover:bg-[#e5a600] text-[#1A2332] py-3 md:py-4 rounded-xl text-base text-[1em] transition-all shadow-[0_4px_15px_rgba(255,185,0,0.2)] hover:shadow-[0_6px_20px_rgba(255,185,0,0.3)] flex justify-center items-center gap-2 mb-4">
پرداخت و ثبت نهایی
<ChevronLeft size={20} strokeWidth={2} />
</Link>
</div>
</div>
</div>
</div>
</main>
);
}