import { trpc } from '@/src/trpc-client'; import { Alert } from 'react-native'; import { useState, useEffect } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { StorageServiceCasual } from 'common-ui/src/services/StorageServiceCasual'; // Cart type definition export type CartType = "regular" | "flash"; // const CART_MODE: 'remote' | 'local' = 'remote'; const CART_MODE: 'remote' | 'local' = 'local'; const getCartStorageKey = (cartType: CartType = "regular"): string => { return cartType === "flash" ? "flash_cart_items" : "cart_items"; }; interface LocalCartItem { id: number; productId: number; quantity: number; slotId: number; addedAt: string; } interface ProductSummary { id: number; name: string; shortDescription?: string | null; longDescription?: string | null; price: string; marketPrice?: string | null; unitNotation: string; images: string[]; isOutOfStock: boolean; store?: { id: number; name: string; description?: string | null } | null; incrementStep: number; productQuantity: number; isFlashAvailable: boolean; flashPrice?: string | null; deliverySlots: Array<{ id: number; deliveryTime: Date; freezeTime: Date }>; specialDeals: Array<{ quantity: string; price: string; validTill: Date }>; } interface CartItem { id: number; productId: number; quantity: number; addedAt: string; product: ProductSummary; subtotal: number; } const getLocalCart = async (cartType: CartType = "regular"): Promise => { const key = getCartStorageKey(cartType); const data = await StorageServiceCasual.getItem(key); return data ? JSON.parse(data) : []; }; const saveLocalCart = async (items: LocalCartItem[], cartType: CartType = "regular"): Promise => { const key = getCartStorageKey(cartType); await StorageServiceCasual.setItem(key, JSON.stringify(items)); const fetchedItems = await getLocalCart(cartType); }; const getNextCartItemId = (items: LocalCartItem[]): number => { const maxId = items.length > 0 ? Math.max(...items.map(item => item.id)) : 0; return maxId + 1; }; const addToLocalCart = async (productId: number, quantity: number, slotId?: number, cartType: CartType = "regular"): Promise => { const items = await getLocalCart(cartType); const existingIndex = items.findIndex(item => item.productId === productId); if (existingIndex >= 0) { items[existingIndex].quantity += quantity; if (slotId !== undefined) { items[existingIndex].slotId = slotId; } } else { const newId = getNextCartItemId(items); const cartItem = { id: newId, productId, quantity, slotId: slotId ?? 0, // Default to 0 if not provided addedAt: new Date().toISOString(), } items.push(cartItem); } await saveLocalCart(items, cartType); return items; }; const updateLocalCartItem = async (itemId: number, quantity: number, cartType: CartType = "regular"): Promise => { const items = await getLocalCart(cartType); const item = items.find(i => i.id === itemId); if (item) { item.quantity = quantity; await saveLocalCart(items, cartType); } return items; }; const removeFromLocalCart = async (itemId: number, cartType: CartType = "regular"): Promise => { const items = await getLocalCart(cartType); const filtered = items.filter(i => i.id !== itemId); await saveLocalCart(filtered, cartType); return filtered; }; const clearLocalCart = async (cartType: CartType = "regular"): Promise => { const key = getCartStorageKey(cartType); await StorageServiceCasual.setItem(key, JSON.stringify([])); }; export function useGetCart(options?: { refetchOnWindowFocus?: boolean; enabled?: boolean; }, cartType: CartType = "regular") { if (CART_MODE === 'remote') { const query = trpc.user.cart.getCart.useQuery(undefined, { refetchOnWindowFocus: options?.refetchOnWindowFocus ?? true, enabled: options?.enabled ?? true, ...options }); return { // Original tRPC returns data: query.data, isLoading: query.isLoading, error: query.error, refetch: query.refetch, // Computed properties cartItems: query.data?.items || [], totalItems: query.data?.totalItems || 0, totalPrice: query.data?.totalAmount || 0, // Helper methods isEmpty: !query.data?.items?.length, hasItems: Boolean(query.data?.items?.length), }; } else { const { data: products } = trpc.user.product.getAllProductsSummary.useQuery(); const query = useQuery({ queryKey: [`local-cart-${cartType}`], queryFn: async () => { const cartItems = await getLocalCart(cartType); // const productMap = Object.fromEntries(products?.map((p: ProductSummary) => [p.id, p]) || []); const productMap = Object.fromEntries(products?.map((p) => [p.id, p]) || []); const items: CartItem[] = cartItems.map(cartItem => { const product = productMap[cartItem.productId]; if (!product) return null as any; return { id: cartItem.id, productId: cartItem.productId, quantity: cartItem.quantity, addedAt: cartItem.addedAt, product, incrementStep: product.incrementStep, subtotal: Number(product.price) * cartItem.quantity, slotId: cartItem.slotId, }; }).filter(Boolean) as CartItem[]; const totalAmount = items.reduce((sum, item) => sum + item.subtotal, 0); return { items, totalItems: items.length, totalAmount, }; }, refetchOnWindowFocus: options?.refetchOnWindowFocus ?? true, enabled: (options?.enabled ?? true) && !!products, }); return { data: query.data, isLoading: query.isLoading, error: query.error, refetch: query.refetch, // Computed properties cartItems: query.data?.items || [], totalItems: query.data?.totalItems || 0, totalPrice: query.data?.totalAmount || 0, // Helper methods isEmpty: !query.data?.items?.length, hasItems: Boolean(query.data?.items?.length), }; } } interface UseAddToCartReturn { mutate: any; mutateAsync: any; isLoading: boolean; error: any; data: any; addToCart: (productId: number, quantity?: number, slotId?: number, onSettled?: (data: any, error: any) => void) => void; addToCartAsync: (productId: number, quantity?: number, slotId?: number) => Promise; } export function useAddToCart(options?: { onSuccess?: (data: any, variables: any) => void; onError?: (error: any) => void; showSuccessAlert?: boolean; showErrorAlert?: boolean; refetchCart?: boolean; }, cartType: CartType = "regular"): UseAddToCartReturn { if (CART_MODE === 'remote') { const utils = trpc.useUtils(); const mutation = trpc.user.cart.addToCart.useMutation({ onSuccess: (data, variables) => { // Default success handling if (options?.showSuccessAlert !== false) { Alert.alert("Success", "Item added to cart!"); } // Auto-refetch cart if requested if (options?.refetchCart) { utils.user.cart.getCart.invalidate(); } // Custom success callback options?.onSuccess?.(data, variables); }, onError: (error) => { // Default error handling if (options?.showErrorAlert !== false) { Alert.alert("Error", error.message || "Failed to add item to cart"); } // Custom error callback options?.onError?.(error); }, }) as any; const addToCart = (productId: number, quantity = 1, slotId?: number, onSettled?: (data: any, error: any) => void) => { if (slotId == null) { throw new Error('slotId is required for adding to cart'); } return mutation.mutate({ productId, quantity, slotId }, { onSettled: (data: any, error: any) => { onSettled?.(data, error); } }); }; return { // Original mutation returns mutate: mutation.mutate, mutateAsync: mutation.mutateAsync, isLoading: mutation.isPending, error: mutation.error, data: mutation.data, addToCart, addToCartAsync: (productId: number, quantity = 1, slotId?: number) => { if (slotId == null) { throw new Error('slotId is required for adding to cart'); } return mutation.mutateAsync({ productId, quantity, slotId }); }, }; } else { const queryClient = useQueryClient(); const mutation = useMutation({ mutationFn: async ({ productId, quantity, slotId }: { productId: number, quantity: number, slotId: number }) => { return await addToLocalCart(productId, quantity, slotId, cartType); }, onSuccess: (data, variables) => { queryClient.invalidateQueries({ queryKey: [`local-cart-${cartType}`] }); if (options?.showSuccessAlert !== false) { Alert.alert("Success", "Item added to cart!"); } options?.onSuccess?.(data, variables); }, onError: (error) => { if (options?.showErrorAlert !== false) { Alert.alert("Error", error.message || "Failed to add item to cart"); } options?.onError?.(error); }, }); const addToCart = (productId: number, quantity = 1, slotId?: number, onSettled?: (data: any, error: any) => void) => { if (slotId == null) { throw new Error('slotId is required for adding to cart'); } return mutation.mutate({ productId, quantity, slotId }, { onSettled: (data: any, error: any) => { onSettled?.(data, error); } }); }; return { mutate: mutation.mutate, mutateAsync: mutation.mutateAsync, isLoading: mutation.isPending, error: mutation.error, data: mutation.data, addToCart, addToCartAsync: (productId: number, quantity = 1, slotId?: number) => { if (slotId == null) { throw new Error('slotId is required for adding to cart'); } return mutation.mutateAsync({ productId, quantity, slotId }); }, }; } } export function useUpdateCartItem(options?: { onSuccess?: (data: any, variables: any) => void; onError?: (error: any) => void; showSuccessAlert?: boolean; showErrorAlert?: boolean; refetchCart?: boolean; }, cartType: CartType = "regular") { if (CART_MODE === 'remote') { const utils = trpc.useUtils(); const mutation = trpc.user.cart.updateCartItem.useMutation({ onSuccess: (data, variables) => { // Default success handling if (options?.showSuccessAlert !== false) { Alert.alert("Success", "Cart item updated!"); } // Auto-refetch cart if requested if (options?.refetchCart) { utils.user.cart.getCart.invalidate(); } // Custom success callback options?.onSuccess?.(data, variables); }, onError: (error) => { // Default error handling if (options?.showErrorAlert !== false) { Alert.alert("Error", error.message || "Failed to update cart item"); } // Custom error callback options?.onError?.(error); }, }); return { // Original mutation returns mutate: mutation.mutate, mutateAsync: mutation.mutateAsync, isLoading: mutation.isPending, error: mutation.error, data: mutation.data, // Helper methods updateCartItem: (itemId: number, quantity: number) => mutation.mutate({ itemId, quantity }), updateCartItemAsync: (itemId: number, quantity: number) => mutation.mutateAsync({ itemId, quantity }), }; } else { const queryClient = useQueryClient(); const mutation = useMutation({ mutationFn: async ({ itemId, quantity }: { itemId: number, quantity: number }) => { return await updateLocalCartItem(itemId, quantity, cartType); }, onSuccess: (data, variables) => { queryClient.invalidateQueries({ queryKey: [`local-cart-${cartType}`] }); if (options?.showSuccessAlert !== false) { Alert.alert("Success", "Cart item updated!"); } options?.onSuccess?.(data, variables); }, onError: (error) => { if (options?.showErrorAlert !== false) { Alert.alert("Error", error.message || "Failed to update cart item"); } options?.onError?.(error); }, }); return { mutate: mutation.mutate, mutateAsync: mutation.mutateAsync, isLoading: mutation.isPending, error: mutation.error, data: mutation.data, updateCartItem: (itemId: number, quantity: number) => mutation.mutate({ itemId, quantity }), updateCartItemAsync: (itemId: number, quantity: number) => mutation.mutateAsync({ itemId, quantity }), }; } } export function useRemoveFromCart(options?: { onSuccess?: (data: any, variables: any) => void; onError?: (error: any) => void; showSuccessAlert?: boolean; showErrorAlert?: boolean; refetchCart?: boolean; }, cartType: CartType = "regular") { if (CART_MODE === 'remote') { const utils = trpc.useUtils(); const mutation = trpc.user.cart.removeFromCart.useMutation({ onSuccess: (data, variables) => { // Default success handling if (options?.showSuccessAlert !== false) { Alert.alert("Success", "Item removed from cart!"); } // Auto-refetch cart if requested if (options?.refetchCart) { utils.user.cart.getCart.invalidate(); } // Custom success callback options?.onSuccess?.(data, variables); }, onError: (error) => { // Default error handling if (options?.showErrorAlert !== false) { Alert.alert("Error", error.message || "Failed to remove item from cart"); } // Custom error callback options?.onError?.(error); }, }); return { // Original mutation returns mutate: mutation.mutate, mutateAsync: mutation.mutateAsync, isLoading: mutation.isPending, error: mutation.error, data: mutation.data, // Helper methods removeFromCart: (itemId: number) => mutation.mutate({ itemId }), removeFromCartAsync: (itemId: number) => mutation.mutateAsync({ itemId }), }; } else { const queryClient = useQueryClient(); const mutation = useMutation({ mutationFn: async ({ itemId }: { itemId: number }) => { return await removeFromLocalCart(itemId, cartType); }, onSuccess: (data, variables) => { queryClient.invalidateQueries({ queryKey: [`local-cart-${cartType}`] }); if (options?.showSuccessAlert !== false) { Alert.alert("Success", "Item removed from cart!"); } options?.onSuccess?.(data, variables); }, onError: (error) => { if (options?.showErrorAlert !== false) { Alert.alert("Error", error.message || "Failed to remove item from cart"); } options?.onError?.(error); }, }); return { mutate: mutation.mutate, mutateAsync: mutation.mutateAsync, isLoading: mutation.isPending, error: mutation.error, data: mutation.data, removeFromCart: (itemId: number) => mutation.mutate({ itemId }), removeFromCartAsync: (itemId: number) => mutation.mutateAsync({ itemId }), }; } } // Export clear cart function for direct use export { clearLocalCart };