Next.js Cart Duplicates Products при входе в системуJavascript

Форум по Javascript
Ответить
Anonymous
 Next.js Cart Duplicates Products при входе в систему

Сообщение Anonymous »

Я строю веб-сайт электронной коммерции, используя Next.js, TypeScript, MongoDB и NextAuth.js. Я по-разному обращаюсь к корзине для покупок для гостевых пользователей и входа в систему: < /p>
Гостевые пользователи: CAR Пользовательский документ MongoDB. Этого не происходит для гостевых пользователей (Cart LocalStorage работает нормально). < /P>
Как это исправить? Похоже, что код в Cartcontext может быть причиной при попытке объединить корзину. < /P>
cartcontext: < /p>
"use client";

// Good way to manage global state(especially where you need access to multiple components)
import React, {
createContext,
useContext,
useState,
ReactNode,
useEffect,
} from "react";
import { useSession } from "next-auth/react";

export interface CartItem {
_id: string;
name: string;
image: string;
price: number;
size?: string;
quantity: number;
}

// functions go here
interface CartContextType {
cart: CartItem[];
addToCart: (item: CartItem) => void;
removeFromCart: (itemId: string, size: string) => void;
calculateTotalPrice: (itemId: string, itemSize: string, itemPrice: number) => number;
updateCartQuantity: (itemId: string, size: string, quantity: number) => void;
syncCartWithBackend: () => Promise;
}

const CartContext = createContext(undefined);

export const CartProvider = ({ children }: { children: ReactNode }) => {
const ls = typeof window !== "undefined" ? window.localStorage : null;
const { data: session, status } = useSession();
const [cart, setCart] = useState([]);
const localStoragekey = "cartItems";

useEffect(() => {
const fetchCart = async () => {
if (status === "authenticated") {
try {
const response = await fetch("/api/cart", { method: "GET" });
if (response.ok) {
const data = await response.json();
//setCart(data.cart);
//syncCartWithBackend();
if(JSON.stringify(data.cart) !== JSON.stringify(cart))
setCart((prevCart) => {
const mergedCart = [...prevCart];
data.cart.forEach((item: CartItem) => {
const existingItem = mergedCart.find(
(cartItem) => cartItem._id === item._id && cartItem.size === item.size
);
if (existingItem) {
// update quantity if item exist in cart
existingItem.quantity += item.quantity;
} else {

mergedCart.push(item);
}
});
return mergedCart;
});
} else {
console.error("Failed to fetch cart from backend:",response.status );
}
} catch (error) {
console.error("Failed to fetch cart from backend:", error);
}
} else if (ls) {
const storedCart = ls.getItem(localStoragekey);
if (storedCart) {
setCart(JSON.parse(storedCart));
}
}
};

if (status === "authenticated" || status === "unauthenticated") {
fetchCart();
}
}, [status]);

// sync after cart is updated
useEffect(() => {
if (status === "unauthenticated" && ls) {
const storedCart = ls.getItem(localStoragekey);
if (storedCart !== JSON.stringify(cart)) {
ls.setItem(localStoragekey, JSON.stringify(cart));
}
}
}, [cart, status, ls]);

// Automatically sync with backend with useeffect and we dont need to call the method in every function
useEffect(() => {
let isSyncing = false;

const syncCartWithBackend = async () => {
if (status === "authenticated" && session?.user?.id && !isSyncing) {
isSyncing = true;
try {
const response = await fetch("/api/cart", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userId: session.user.id, cartItems: cart }),
});

if (!response.ok) {
console.error("Failed to sync cart with backend:", response.status);
}
} catch (error) {
console.error("Error syncing cart:", error);
} finally {
isSyncing = false;
}
}
};

if(status === "authenticated") {
syncCartWithBackend();
}
}, [cart, status, session]);

const addToCart = (item: CartItem) => {
setCart((prevCart) => {
const existingItem = prevCart.find(
(cartItem) => cartItem._id === item._id && cartItem.size === item.size
);

if (existingItem) {
//update quantity if item is already in cart with same size
return prevCart.map((cartItem) =>
cartItem._id === item._id && cartItem.size === item.size
? { ...cartItem, quantity: Math.max(1,cartItem.quantity + 1) } // prevent quantity being below 1
: cartItem
);
} else {
//add new item to cart
return [...prevCart, { ...item, quantity: 1 }];
}
});
};

const removeFromCart = (itemId: string, size: string) => {
setCart((prevCart) =>
prevCart.filter(
(cartItem) => !(cartItem._id === itemId && cartItem.size === size)
)
);
};

const updateCartQuantity = (
itemId: string,
size: string,
quantity: number
) => {
setCart((prevCart) =>
prevCart
.map((cartItem) =>
cartItem._id === itemId && cartItem.size === size
? {
...cartItem,
quantity: Math.max(0, cartItem.quantity + quantity),
}
: cartItem
)
.filter((cartItem) => cartItem.quantity > 0)
);
};

const calculateTotalPrice = (
itemId: string,
itemSize: string | undefined,
itemPrice: number
) => {
const totalQuantity = cart
.filter((item) => item._id === itemId && item.size === itemSize || item.size === "onesize")
.reduce((acc, item) => acc + item.quantity, 0);
return totalQuantity * itemPrice;
};

return (
{},
}}
>
{children}

);
};

//Function to use the cart
export const useCart = () => {
const context = useContext(CartContext);
if (!context) {
throw new Error();
}
return context;
};



Подробнее здесь: https://stackoverflow.com/questions/794 ... -logged-in
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»