edit/delete address api
This commit is contained in:
@@ -15,7 +15,7 @@ import {
|
|||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import PaymentMethodsSection from "@/components/PaymentMethods";
|
import PaymentMethodsSection from "@/components/PaymentMethods";
|
||||||
import { getCartApi } from "@/public/src/services/cart/api";
|
import { getCartApi } from "@/public/src/services/cart/api";
|
||||||
import { fetchUserAddresses, type Address, addAddressApi, NewAddressData } from "@/public/src/services/address/api";
|
import { fetchUserAddresses, type Address, addAddressApi, NewAddressData, updateAddressApi, deleteAddressApi } from "@/public/src/services/address/api";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -133,12 +133,122 @@ export default function CheckoutPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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) => {
|
const parsePrice = (priceStr?: number | null | string) => {
|
||||||
if (!priceStr) return 0;
|
if (!priceStr) return 0;
|
||||||
return Number(priceStr.toString().replace(/,/g, ''));
|
return Number(priceStr.toString().replace(/,/g, ''));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ۴. استفاده از اطلاعات سرور در صورت لاگین بودن، در غیر این صورت استفاده از Context
|
// ۴. استفاده از اطلاعات سرور در صورت لاگین بودن، در غیر این صورت استفاده از Context
|
||||||
const totalPrice = isAuthenticated && serverSummary
|
const totalPrice = isAuthenticated && serverSummary
|
||||||
? serverSummary.totalPrice || serverSummary.total || 0
|
? serverSummary.totalPrice || serverSummary.total || 0
|
||||||
@@ -239,11 +349,13 @@ export default function CheckoutPage() {
|
|||||||
{showNewAddressForm ? (
|
{showNewAddressForm ? (
|
||||||
<div className="bg-white rounded-[1rem] p-6 shadow-sm space-y-6 border border-gray-100">
|
<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">
|
<div className="flex justify-between items-center border-b pb-4">
|
||||||
<button className="text-lg cursor-pointer font-bold text-gray-800">افزودن آدرس جدید</button>
|
<button className="text-lg cursor-pointer font-bold text-gray-800">
|
||||||
|
{editingAddressId ? 'ویرایش آدرس' : 'افزودن آدرس جدید'}
|
||||||
|
</button>
|
||||||
{addresses.length > 0 && (
|
{addresses.length > 0 && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowNewAddressForm(false)}
|
onClick={handleCancelForm}
|
||||||
className="text-sm cursor-pointer text-red-500 hover:text-red-700"
|
className="text-sm cursor-pointer text-red-500 hover:text-red-700"
|
||||||
>
|
>
|
||||||
انصراف
|
انصراف
|
||||||
@@ -370,10 +482,10 @@ export default function CheckoutPage() {
|
|||||||
<div className="pt-4">
|
<div className="pt-4">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={handleAddNewAddress}
|
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"
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -386,7 +498,11 @@ export default function CheckoutPage() {
|
|||||||
<h2 className="text-lg font-bold text-gray-800">انتخاب آدرس ارسال</h2>
|
<h2 className="text-lg font-bold text-gray-800">انتخاب آدرس ارسال</h2>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowNewAddressForm(true)}
|
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"
|
className="text-sm cursor-pointer text-blue-600 hover:text-blue-800 font-medium flex items-center gap-1"
|
||||||
>
|
>
|
||||||
<span>+</span> افزودن آدرس جدید
|
<span>+</span> افزودن آدرس جدید
|
||||||
@@ -402,118 +518,89 @@ export default function CheckoutPage() {
|
|||||||
{addresses.map((address) => (
|
{addresses.map((address) => (
|
||||||
<label
|
<label
|
||||||
key={address.id}
|
key={address.id}
|
||||||
className={`block border rounded-xl p-4 cursor-pointer transition-all ${selectedAddressId === 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]/5'
|
? 'border-[#ffb900] bg-[#ffb900]/[0.03] ring-1 ring-[#ffb900]/20 shadow-sm'
|
||||||
: 'border-gray-100 hover:border-gray-200'
|
: 'border-gray-200 bg-white hover:border-gray-300 hover:shadow-sm'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-start gap-3">
|
<div className="flex items-start gap-4">
|
||||||
<div className="pt-1">
|
{/* رادیو باتن */}
|
||||||
|
<div className="pt-0.5 relative flex items-center justify-center">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
name="selectedAddress"
|
name="selectedAddress"
|
||||||
value={address.id}
|
value={address.id}
|
||||||
checked={selectedAddressId === address.id}
|
checked={selectedAddressId === address.id}
|
||||||
onChange={() => setSelectedAddressId(address.id)}
|
onChange={() => setSelectedAddressId(address.id)}
|
||||||
className="w-4 h-4 border-[#ffb900] focus:ring-[#ffb900] cursor-pointer"
|
// حذف استایل پیشفرض و اعمال بوردر و رنگ سفارشی
|
||||||
|
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>
|
||||||
<div className="flex-1">
|
|
||||||
<div className="flex justify-between items-start">
|
|
||||||
<p className="font-medium text-gray-900">{address.addressLine}</p>
|
|
||||||
|
<div className="flex-1 space-y-3">
|
||||||
|
{/* عنوان و متن آدرس */}
|
||||||
|
<div>
|
||||||
{address.title && (
|
{address.title && (
|
||||||
<span className="bg-gray-100 text-gray-600 text-xs px-2 py-1 rounded">
|
<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}
|
{address.title}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
<p className="font-medium text-gray-800 leading-relaxed text-sm md:text-base">
|
||||||
|
{address.addressLine}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 text-sm text-gray-600 flex flex-wrap gap-y-1 gap-x-4">
|
|
||||||
<span className="flex items-center gap-1">
|
{/* جزئیات آدرس (مینیمال شده) */}
|
||||||
<span className="font-semibold text-gray-500">گیرنده:</span> {address.recipientName}
|
<div className="flex flex-wrap items-center text-xs md:text-sm text-gray-500 gap-x-2 gap-y-1.5">
|
||||||
</span>
|
<span>{address.recipientName}</span>
|
||||||
<span className="flex items-center gap-1">
|
<span className="text-gray-300 text-[10px]">●</span>
|
||||||
<span className="font-semibold text-gray-500">موبایل:</span> {address.phone}
|
<span dir="ltr">{address.phone}</span>
|
||||||
</span>
|
<span className="text-gray-300 text-[10px]">●</span>
|
||||||
<span className="flex items-center gap-1">
|
<span>کد پستی: {address.postalCode}</span>
|
||||||
<span className="font-semibold text-gray-500">کد پستی:</span> {address.postalCode}
|
<span className="text-gray-300 text-[10px]">●</span>
|
||||||
</span>
|
|
||||||
<span>
|
<span>
|
||||||
<span className="font-semibold text-gray-500">پلاک:</span> {address.plaque} {address.unit ? `- واحد: ${address.unit}` : ''}
|
پلاک {address.plaque}
|
||||||
|
{address.unit ? `، واحد ${address.unit}` : ''}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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>
|
</label>
|
||||||
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
|
<div className="bg-white rounded-[1rem] p-6 shadow-sm space-y-4">
|
||||||
|
|
||||||
{/* <div className="bg-white rounded-[1rem] p-6 md:p-8 shadow-sm">
|
|
||||||
<div className="flex items-center gap-3 mb-6 pb-4 border-b border-gray-100">
|
|
||||||
<div className="bg-[#1A2332]/5 p-2 rounded-lg text-[#1A2332]">
|
|
||||||
<MapPin size={20} />
|
|
||||||
</div>
|
|
||||||
<h2 className="text-base md:text-lg font-bold text-[#1A2332]">آدرس پستی</h2>
|
|
||||||
</div>
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-5 mb-5">
|
|
||||||
<div className="space-y-2">
|
|
||||||
<label className="text-sm font-medium text-gray-600 block">استان</label>
|
|
||||||
<select className="w-full bg-gray-50 text-[13px] border border-gray-200 text-[#1A2332] rounded-xl px-4 py-3 outline-none focus:ring-2 focus:ring-[#ffb900]/40 focus:border-[#ffb900] transition-all appearance-none cursor-pointer">
|
|
||||||
<option value="">انتخاب استان...</option>
|
|
||||||
<option value="tehran">تهران</option>
|
|
||||||
<option value="alborz">البرز</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div className="space-y-2">
|
|
||||||
<label className="text-sm font-medium text-gray-600 block">شهر</label>
|
|
||||||
<select className="w-full text-[13px] bg-gray-50 border border-gray-200 text-[#1A2332] rounded-xl px-4 py-3 outline-none focus:ring-2 focus:ring-[#ffb900]/40 focus:border-[#ffb900] transition-all appearance-none cursor-pointer">
|
|
||||||
<option value="">انتخاب شهر...</option>
|
|
||||||
<option value="tehran">تهران</option>
|
|
||||||
<option value="karaj">کرج</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="space-y-2 mb-5">
|
|
||||||
<label className="text-sm font-medium text-gray-600 block">آدرس دقیق پستی</label>
|
|
||||||
<textarea rows={3} placeholder="خیابان، کوچه، پلاک، واحد..." className="w-full text-[13px] bg-gray-50 border border-gray-200 text-[#1A2332] rounded-xl px-4 py-3 outline-none focus:ring-2 focus:ring-[#ffb900]/40 focus:border-[#ffb900] transition-all placeholder:text-gray-400 resize-none" />
|
|
||||||
</div>
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-5 mb-5">
|
|
||||||
<div className=" space-y-2">
|
|
||||||
<label className="text-sm font-medium text-gray-600 block">کد پستی (۱۰ رقمی)</label>
|
|
||||||
<input type="text" placeholder="1234567890" className="w-full bg-gray-50 border border-gray-200 text-[#1A2332] rounded-xl px-4 py-3 outline-none focus:ring-2 focus:ring-[#ffb900]/40 focus:border-[#ffb900] transition-all placeholder:text-gray-400 placeholder:text-[13px]" />
|
|
||||||
</div>
|
|
||||||
<div className="space-y-2">
|
|
||||||
<label className="text-sm font-medium text-gray-600 block">ایمیل</label>
|
|
||||||
<input type="email" placeholder="test@email.com" className="w-full bg-gray-50 border border-gray-200 text-[#1A2332] rounded-xl px-4 py-3 outline-none focus:ring-2 focus:ring-[#ffb900]/40 focus:border-[#ffb900] transition-all placeholder:text-gray-400 placeholder:text-[13px]" />
|
|
||||||
</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="bg-white rounded-[1rem] pt-4 pb-4">
|
|
||||||
<div className="flex items-center gap-3 mb-6 pb-4 ">
|
<div className="flex items-center gap-3 mb-6 pb-4 ">
|
||||||
<div className="bg-[#1A2332]/5 p-2 rounded-lg text-[#1A2332]">
|
<div className="bg-[#1A2332]/5 p-2 rounded-lg text-[#1A2332]">
|
||||||
<Truck size={20} />
|
<Truck size={20} />
|
||||||
@@ -549,6 +636,28 @@ export default function CheckoutPage() {
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</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 className="w-full border-t-2 border-dashed border-gray-100 my-6"></div>
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,24 @@ export interface NewAddressData {
|
|||||||
isDefault?: boolean;
|
isDefault?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UpdateAddressResponse {
|
||||||
|
success: boolean;
|
||||||
|
statusCode: number;
|
||||||
|
data: Address;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DeleteAddressResponse {
|
||||||
|
success: boolean;
|
||||||
|
statusCode: number;
|
||||||
|
path: string;
|
||||||
|
timestamp: string;
|
||||||
|
data: {
|
||||||
|
message: string;
|
||||||
|
addressId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export const fetchUserAddresses = async (): Promise<Address[]> => {
|
export const fetchUserAddresses = async (): Promise<Address[]> => {
|
||||||
// این تابع روی کلاینت باید صدا زده بشه (چون localStorage داریم)
|
// این تابع روی کلاینت باید صدا زده بشه (چون localStorage داریم)
|
||||||
const headers = getAuthHeaders();
|
const headers = getAuthHeaders();
|
||||||
@@ -74,13 +92,13 @@ export const fetchUserAddresses = async (): Promise<Address[]> => {
|
|||||||
export const addAddressApi = async (addressData: NewAddressData): Promise<Address> => {
|
export const addAddressApi = async (addressData: NewAddressData): Promise<Address> => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/users/me/addresses`, {
|
const response = await fetch(`${API_BASE_URL}/users/me/addresses`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: getAuthHeaders(),
|
headers: getAuthHeaders(),
|
||||||
body: JSON.stringify(addressData),
|
body: JSON.stringify(addressData),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Network response was not ok for adding address');
|
throw new Error('Network response was not ok for adding address');
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
@@ -89,4 +107,45 @@ export const addAddressApi = async (addressData: NewAddressData): Promise<Addres
|
|||||||
console.error('Error adding new address:', error);
|
console.error('Error adding new address:', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateAddressApi = async (
|
||||||
|
addressId: string,
|
||||||
|
addressData: NewAddressData | Partial<NewAddressData>
|
||||||
|
): Promise<UpdateAddressResponse> => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${API_BASE_URL}/users/me/addresses/${addressId}`, {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: getAuthHeaders(),
|
||||||
|
body: JSON.stringify(addressData),
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(result.message || 'خطا در ویرایش آدرس');
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Update address error:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// تابع حذف آدرس (DELETE)
|
||||||
|
export const deleteAddressApi = async (addressId: string): Promise<DeleteAddressResponse> => {
|
||||||
|
const token = localStorage.getItem('refreshToken');
|
||||||
|
|
||||||
|
const response = await fetch(`${API_BASE_URL}/users/me/addresses/${addressId}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('خطا در ارتباط با سرور برای حذف آدرس');
|
||||||
|
}
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user