257 lines
6.9 KiB
TypeScript
257 lines
6.9 KiB
TypeScript
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
|
import { useAuthToken } from "../hooks/use-root-data";
|
|
import { useEffect, useState } from "react";
|
|
import { createShoppingCartApi } from "~/utils/api-client-factory";
|
|
|
|
// Hook to get all carts
|
|
export function useGetAllCarts() {
|
|
const token = useAuthToken();
|
|
return useQuery({
|
|
queryKey: ["carts", "list"],
|
|
queryFn: async () => {
|
|
console.log("📥 Fetching cart list...");
|
|
try {
|
|
const cartApi = createShoppingCartApi(token);
|
|
const result = await cartApi.apiShoppingcartV1CartList();
|
|
return result;
|
|
} catch (error) {
|
|
console.error("❌ Error fetching carts:", error);
|
|
return [];
|
|
}
|
|
},
|
|
// Run even without token for guest carts
|
|
retry: 1,
|
|
staleTime: 30 * 60 * 1000, // 30 seconds - balance between freshness and performance
|
|
refetchOnWindowFocus: false,
|
|
});
|
|
}
|
|
|
|
// Hook to get cart count
|
|
export function useGetCartCount() {
|
|
const token = useAuthToken();
|
|
|
|
return useQuery({
|
|
queryKey: ["carts", "count"],
|
|
queryFn: async () => {
|
|
try {
|
|
if (!token) return 0;
|
|
|
|
const cartApi = createShoppingCartApi(token);
|
|
const carts = await cartApi.apiShoppingcartV1CartList();
|
|
|
|
// Calculate total items across all carts
|
|
return carts.reduce((total, cart) => {
|
|
return total + (cart.items?.length || 0);
|
|
}, 0);
|
|
} catch (error) {
|
|
console.error("Error getting cart count:", error);
|
|
return 0;
|
|
}
|
|
},
|
|
enabled: !!token, // Only run if user is authenticated
|
|
staleTime: 2 * 60 * 1000, // 2 minutes - cart count doesn't change often
|
|
gcTime: 5 * 60 * 1000, // 5 minutes
|
|
retry: 1,
|
|
});
|
|
}
|
|
|
|
// Hook to add item to cart
|
|
export function useAddToCart() {
|
|
const token = useAuthToken();
|
|
const queryClient = useQueryClient();
|
|
|
|
return useMutation({
|
|
mutationFn: async ({
|
|
variantId,
|
|
quantity,
|
|
}: {
|
|
variantId: string;
|
|
quantity: number;
|
|
}) => {
|
|
try {
|
|
const cartApi = createShoppingCartApi(token);
|
|
await cartApi.apiShoppingcartV1CartAddCreate({
|
|
data: {
|
|
productVariantId: variantId,
|
|
quantity: quantity,
|
|
},
|
|
});
|
|
return true;
|
|
} catch (error) {
|
|
console.error("Failed to add item to cart:", error);
|
|
return false;
|
|
}
|
|
},
|
|
onSuccess: async () => {
|
|
// Invalidate and refetch cart queries immediately
|
|
await Promise.all([
|
|
queryClient.invalidateQueries({
|
|
queryKey: ["carts", "list"],
|
|
refetchType: "all", // Refetch all queries, not just active ones
|
|
}),
|
|
queryClient.invalidateQueries({
|
|
queryKey: ["carts", "count"],
|
|
refetchType: "all",
|
|
}),
|
|
]);
|
|
},
|
|
onError: (error) => {
|
|
console.error("Failed to add item to cart:", error);
|
|
},
|
|
});
|
|
}
|
|
|
|
// Hook to update cart item quantity
|
|
export function useUpdateCartItemQuantity() {
|
|
const token = useAuthToken();
|
|
const queryClient = useQueryClient();
|
|
|
|
return useMutation({
|
|
mutationFn: async ({
|
|
itemId,
|
|
quantity,
|
|
}: {
|
|
itemId: string;
|
|
quantity: number;
|
|
}) => {
|
|
try {
|
|
const cartApi = createShoppingCartApi(token);
|
|
await cartApi.apiShoppingcartV1CartEditPartialUpdate({
|
|
data: {
|
|
itemId,
|
|
quantity,
|
|
},
|
|
});
|
|
return true;
|
|
} catch (error) {
|
|
console.error("Error updating cart item quantity:", error);
|
|
return false;
|
|
}
|
|
},
|
|
onSuccess: async () => {
|
|
// Invalidate and refetch all cart queries immediately
|
|
await Promise.all([
|
|
queryClient.invalidateQueries({
|
|
queryKey: ["carts", "list"],
|
|
refetchType: "all",
|
|
}),
|
|
queryClient.invalidateQueries({
|
|
queryKey: ["carts", "count"],
|
|
refetchType: "all",
|
|
}),
|
|
queryClient.invalidateQueries({
|
|
queryKey: ["carts", "detail"],
|
|
refetchType: "all",
|
|
}),
|
|
]);
|
|
},
|
|
});
|
|
}
|
|
|
|
// Hook to remove item from cart
|
|
export function useRemoveFromCart() {
|
|
const token = useAuthToken();
|
|
const queryClient = useQueryClient();
|
|
|
|
return useMutation({
|
|
mutationFn: async (itemId: string) => {
|
|
try {
|
|
const cartApi = createShoppingCartApi(token);
|
|
await cartApi.apiShoppingcartV1CartRemoveDelete({ itemId });
|
|
return true;
|
|
} catch (error) {
|
|
console.error("Error removing item from cart:", error);
|
|
return false;
|
|
}
|
|
},
|
|
onSuccess: async () => {
|
|
// Invalidate and refetch all cart queries immediately
|
|
await Promise.all([
|
|
queryClient.invalidateQueries({
|
|
queryKey: ["carts", "list"],
|
|
refetchType: "all",
|
|
}),
|
|
queryClient.invalidateQueries({
|
|
queryKey: ["carts", "count"],
|
|
refetchType: "all",
|
|
}),
|
|
queryClient.invalidateQueries({
|
|
queryKey: ["carts", "detail"],
|
|
refetchType: "all",
|
|
}),
|
|
]);
|
|
},
|
|
});
|
|
}
|
|
|
|
// Hook to clear cart
|
|
export function useClearCart() {
|
|
const token = useAuthToken();
|
|
const queryClient = useQueryClient();
|
|
|
|
return useMutation({
|
|
mutationFn: async (cartId: string) => {
|
|
try {
|
|
const cartApi = createShoppingCartApi(token);
|
|
await cartApi.apiShoppingcartV1CartClearCreate({ cartId });
|
|
return true;
|
|
} catch (error) {
|
|
console.error("Error clearing cart:", error);
|
|
return false;
|
|
}
|
|
},
|
|
onSuccess: async () => {
|
|
// Invalidate and refetch all cart queries immediately
|
|
await Promise.all([
|
|
queryClient.invalidateQueries({
|
|
queryKey: ["carts", "list"],
|
|
refetchType: "all",
|
|
}),
|
|
queryClient.invalidateQueries({
|
|
queryKey: ["carts", "count"],
|
|
refetchType: "all",
|
|
}),
|
|
queryClient.invalidateQueries({
|
|
queryKey: ["carts", "detail"],
|
|
refetchType: "all",
|
|
}),
|
|
]);
|
|
},
|
|
});
|
|
}
|
|
|
|
// Hook to get details of a specific cart
|
|
export function useGetCartDetails(cartId: string) {
|
|
const token = useAuthToken();
|
|
|
|
return useQuery({
|
|
queryKey: ["carts", "detail", cartId],
|
|
queryFn: async () => {
|
|
try {
|
|
const cartApi = createShoppingCartApi(token);
|
|
return await cartApi.apiShoppingcartV1CartRead({ cartId });
|
|
} catch (error) {
|
|
console.error(`Error fetching cart ${cartId}:`, error);
|
|
return null;
|
|
}
|
|
},
|
|
enabled: !!cartId, // Only run if we have a cart ID
|
|
retry: 1,
|
|
staleTime: 30 * 60 * 1000, // 30 seconds - balance between freshness and performance
|
|
refetchOnWindowFocus: false,
|
|
});
|
|
}
|
|
export const useCartCount = () => {
|
|
const [count, setCount] = useState(0);
|
|
const { data: cartCount, isLoading } = useGetCartCount();
|
|
|
|
// Update local state whenever the query data changes
|
|
useEffect(() => {
|
|
if (!isLoading && cartCount !== undefined) {
|
|
setCount(cartCount);
|
|
}
|
|
}, [cartCount, isLoading]);
|
|
|
|
return count;
|
|
};
|