add cart API's (add , delete , get)
This commit is contained in:
@@ -4,7 +4,7 @@ import { useCart } from "@/components/context/cartcontext";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react"; // اضافه شدن useState
|
||||
import { useState, useEffect } from "react"; // اضافه شدن useEffect
|
||||
import {
|
||||
Trash2,
|
||||
ShoppingBag,
|
||||
@@ -16,40 +16,140 @@ import {
|
||||
CreditCard
|
||||
} from "lucide-react";
|
||||
|
||||
// مسیر ایمپورت کامپوننت Notlogin را بر اساس ساختار پوشهبندی خود تنظیم کنید
|
||||
import NotLogin from "@/components/Notlogin";
|
||||
import { getCartApi } from "@/public/src/services/cart/api"; // ایمپورت API
|
||||
import { clearServerCartApi } from "@/public/src/services/cart/api";
|
||||
|
||||
export default function CartPage() {
|
||||
const { cart, clearCart, addToCart, decreaseQuantity } = useCart();
|
||||
const {
|
||||
cart,
|
||||
clearCart,
|
||||
addToCart,
|
||||
decreaseQuantity,
|
||||
} = useCart();
|
||||
|
||||
// const handleClearAll = async () => {
|
||||
// // ۱. پاک کردن استیت لوکال
|
||||
// clearCart();
|
||||
|
||||
// const token = typeof window !== 'undefined' ? localStorage.getItem('refreshToken') : null;
|
||||
// if (token) {
|
||||
// try {
|
||||
// // ۲. پاک کردن از سرور
|
||||
// await clearServerCartApi();
|
||||
|
||||
// // ۳. آپدیت کردن صفحه برای دریافت دیتای جدید سرور (سبد خالی)
|
||||
// router.refresh();
|
||||
|
||||
// } catch (error) {
|
||||
// console.error(error);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
// استیت برای مدیریت نمایش مودال/کامپوننت لاگین نشدهها
|
||||
const [showNotLogin, setShowNotLogin] = useState(false);
|
||||
|
||||
// --- استیتهای مربوط به دریافت اطلاعات سرور ---
|
||||
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
||||
const [serverCartItems, setServerCartItems] = useState<any[]>([]);
|
||||
const [serverSummary, setServerSummary] = useState<any>(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
// --- منطق اصلاح شده دکمه حذف همه ---
|
||||
const handleClearAll = async () => {
|
||||
// ۱. پاک کردن استیتهای لوکال و استیتهای همین صفحه
|
||||
clearCart();
|
||||
setServerCartItems([]);
|
||||
setServerSummary(null);
|
||||
|
||||
// ۲. ارسال دستور مستقیم به هدر برای خالی شدن درجا (بدون درنگ)
|
||||
window.dispatchEvent(new Event('cartCleared'));
|
||||
|
||||
// ۳. فراخوانی API برای پاک کردن دیتابیس در پسزمینه
|
||||
const token = typeof window !== 'undefined' ? localStorage.getItem('accessToken') : null;
|
||||
if (token) {
|
||||
try {
|
||||
await clearServerCartApi(); // متد DELETE
|
||||
// اینجا دیگر نیازی به cartUpdated نیست چون هدر را به صورت دستی خالی کردیم
|
||||
} catch (error) {
|
||||
console.error("خطا در پاک کردن سبد خرید سرور:", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// --- useEffect برای بررسی لاگین و دریافت دیتای سرور ---
|
||||
useEffect(() => {
|
||||
const fetchServerCart = async () => {
|
||||
const token = localStorage.getItem('accessToken');
|
||||
if (token) {
|
||||
setIsLoggedIn(true);
|
||||
try {
|
||||
const data = await getCartApi();
|
||||
if (data) {
|
||||
setServerCartItems(data.items || []);
|
||||
setServerSummary(data.summary || null);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("خطا در دریافت اطلاعات سبد خرید:", error);
|
||||
}
|
||||
} else {
|
||||
setIsLoggedIn(false);
|
||||
}
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
fetchServerCart();
|
||||
}, []);
|
||||
|
||||
|
||||
// بررسی لاگین کاربر
|
||||
const handleCheckoutNavigation = () => {
|
||||
const token = localStorage.getItem('accessToken');
|
||||
if (token) {
|
||||
// اگر لاگین بود برود به چک اوت
|
||||
router.push('/checkout');
|
||||
} else {
|
||||
// اگر لاگین نبود، کامپوننت Notlogin نمایش داده شود
|
||||
setShowNotLogin(true);
|
||||
}
|
||||
};
|
||||
|
||||
// تبدیل رشته قیمت به عدد
|
||||
const parsePrice = (priceStr?: number | null) => {
|
||||
const parsePrice = (priceStr?: number | string | null) => {
|
||||
if (!priceStr) return 0;
|
||||
return Number(priceStr.toString().replace(/,/g, ''));
|
||||
};
|
||||
|
||||
// محاسبه قیمت کل و تعداد کل
|
||||
const totalPrice = cart.reduce((total, item) => total + (parsePrice(item.price) * item.quantity), 0);
|
||||
const totalItems = cart.reduce((total, item) => total + item.quantity, 0);
|
||||
// --- منطق یکپارچهسازی: اگر لاگین بود دیتای سرور، در غیر اینصورت دیتای لوکال ---
|
||||
const displayCart = isLoggedIn
|
||||
? serverCartItems.map(item => ({
|
||||
id: item.product?.id || item.productId,
|
||||
title: item.product?.title || "بدون نام",
|
||||
brand: item.product?.brand || "متفرقه",
|
||||
price: item.unitPrice || item.product?.price || 0,
|
||||
quantity: item.quantity || 1,
|
||||
image: item.product?.mainImageUrl || item.product?.image || "/placeholder.png"
|
||||
}))
|
||||
: cart;
|
||||
|
||||
// دیزاین حالت سبد خرید خالی
|
||||
if (cart.length === 0) {
|
||||
// محاسبه قیمت کل و تعداد کل
|
||||
const totalPrice = isLoggedIn && serverSummary
|
||||
? serverSummary.totalPrice || serverSummary.total || 0
|
||||
: cart.reduce((total, item) => total + (parsePrice(item.price) * item.quantity), 0);
|
||||
|
||||
const totalItems = isLoggedIn && serverSummary
|
||||
? serverSummary.totalQuantity || serverSummary.itemsCount || 0
|
||||
: cart.reduce((total, item) => total + item.quantity, 0);
|
||||
|
||||
// --- جلوگیری از پرش تصویر قبل از لود شدن دیتا ---
|
||||
if (isLoading) {
|
||||
return <div className="min-h-screen bg-gray-50/50 flex items-center justify-center">در حال بارگذاری...</div>;
|
||||
}
|
||||
|
||||
// دیزاین حالت سبد خرید خالی (تغییر cart.length به displayCart.length)
|
||||
if (displayCart.length === 0) {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50/50 flex flex-col items-center justify-center p-6">
|
||||
<div className="bg-white p-12 rounded-[3rem] shadow-sm border border-gray-100 flex flex-col items-center max-w-md w-full text-center">
|
||||
@@ -61,7 +161,7 @@ export default function CartPage() {
|
||||
<p className="text-gray-500 mb-10 leading-relaxed text-sm">
|
||||
هنوز هیچ محصولی به سبد خرید خود اضافه نکردهاید. برای مشاهده محصولات به صفحه اصلی برگردید.
|
||||
</p>
|
||||
<Link href="/" className="w-full bg-[#ffb900] hover:bg-[#e5a600] text-black font-bold text-lg px-8 py-4 rounded-2xl transition-all shadow-[0_4px_20px_rgba(255,185,0,0.3)] hover:shadow-[0_6px_25px_rgba(255,185,0,0.4)] flex items-center justify-center gap-2">
|
||||
<Link href="/products" className="w-full bg-[#ffb900] hover:bg-[#e5a600] text-black font-bold text-lg px-8 py-4 rounded-2xl transition-all shadow-[0_4px_20px_rgba(255,185,0,0.3)] hover:shadow-[0_6px_25px_rgba(255,185,0,0.4)] flex items-center justify-center gap-2">
|
||||
بازگشت به فروشگاه
|
||||
<ChevronLeft size={20} />
|
||||
</Link>
|
||||
@@ -72,11 +172,9 @@ export default function CartPage() {
|
||||
|
||||
return (
|
||||
<main className="bg-gray-50/30 min-h-screen pb-20">
|
||||
{/* رندر کردن کامپوننت Notlogin به صورت شرطی */}
|
||||
{/* اگر نیاز است که کاربر بتواند آن را ببندد، پراپ onClose را به آن پاس بدهید */}
|
||||
{showNotLogin && (
|
||||
<NotLogin
|
||||
buttonText="بازگشت به سبد خرید"
|
||||
<NotLogin
|
||||
buttonText="بازگشت به سبد خرید"
|
||||
onClose={() => setShowNotLogin(false)} />
|
||||
)}
|
||||
|
||||
@@ -106,7 +204,6 @@ export default function CartPage() {
|
||||
<span className="text-[10px] sm:text-sm font-bold text-[#1A2332] text-center">سبد خرید</span>
|
||||
</Link>
|
||||
|
||||
{/* کلیک روی آیکون اطلاعات ارسال */}
|
||||
<div onClick={handleCheckoutNavigation} className="flex flex-col items-center w-1/3 cursor-pointer group">
|
||||
<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] group-hover:border-[#ffb900] transition-colors">
|
||||
<Truck className="w-4 h-4 sm:w-5 sm:h-5" strokeWidth={2} />
|
||||
@@ -130,14 +227,15 @@ export default function CartPage() {
|
||||
<div className="bg-white rounded-[1rem] p-4 md:p-8 shadow-sm ">
|
||||
<div className="flex justify-between items-center mb-6 pb-6 border-b border-gray-100">
|
||||
<h2 className="text-base md:text-lg font-bold text-gray-800">محصولات انتخاب شده</h2>
|
||||
<button onClick={clearCart} className="text-xs md:text-sm text-red-500 hover:text-red-700 transition flex items-center gap-1.5 bg-red-50 hover:bg-red-100 px-3 py-1.5 rounded-lg">
|
||||
<button onClick={handleClearAll} className="text-xs cursor-pointer md:text-sm text-red-500 hover:text-red-700 transition flex items-center gap-1.5 bg-red-50 hover:bg-red-100 px-3 py-1.5 rounded-lg">
|
||||
<Trash2 size={16} />
|
||||
حذف همه
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-6">
|
||||
{cart.map((item) => {
|
||||
{/* حلقه مپ روی displayCart اعمال شده است */}
|
||||
{displayCart.map((item) => {
|
||||
const itemTotal = parsePrice(item.price) * item.quantity;
|
||||
return (
|
||||
<div key={item.id} className="group flex flex-col sm:flex-row gap-4 sm:gap-6 items-start sm:items-center border-b border-gray-50 pb-6 last:border-0 last:pb-0">
|
||||
@@ -153,7 +251,7 @@ export default function CartPage() {
|
||||
{item.price ? `${itemTotal.toLocaleString('fa-IR')} ت` : 'استعلام'}
|
||||
</span>
|
||||
<div className="flex items-center gap-1 bg-gray-50 border border-gray-200 rounded-full p-1 shadow-sm">
|
||||
<button onClick={() => addToCart(item)} className="w-7 h-7 md:w-8 md:h-8 flex items-center justify-center rounded-full bg-white text-gray-600 hover:text-green-600 hover:shadow-sm transition-all">
|
||||
<button onClick={() => addToCart(item as any)} className="w-7 h-7 md:w-8 md:h-8 flex items-center justify-center rounded-full bg-white text-gray-600 hover:text-green-600 hover:shadow-sm transition-all">
|
||||
<Plus size={14} strokeWidth={2.5} />
|
||||
</button>
|
||||
<span className="text-xs md:text-sm font-bold text-gray-800 w-6 text-center">{item.quantity}</span>
|
||||
@@ -191,10 +289,9 @@ export default function CartPage() {
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* دکمه تایید و ادامه */}
|
||||
<button
|
||||
onClick={handleCheckoutNavigation}
|
||||
className="w-full bg-[#ffb900] hover:bg-[#e5a600] text-black py-3 md:py-4 rounded-xl font-bold text-base md:text-lg 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-6"
|
||||
className="w-full bg-[#ffb900] cursor-pointer hover:bg-[#e5a600] text-black py-3 md:py-4 rounded-xl font-bold text-base md:text-lg 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-6"
|
||||
>
|
||||
تایید و ادامه
|
||||
<ChevronLeft size={20} />
|
||||
|
||||
Reference in New Issue
Block a user