feat: implement wishlist feature with admin toggle
- Add WishlistController with full CRUD API - Create wishlist page in My Account - Add heart icon to all product card layouts (always visible) - Implement useWishlist hook for state management - Add wishlist toggle in admin Settings > Customer - Fix wishlist menu visibility based on admin settings - Fix double navigation in wishlist page - Fix variable product navigation to use React Router - Add TypeScript type casting fix for addresses
This commit is contained in:
111
customer-spa/src/hooks/useWishlist.ts
Normal file
111
customer-spa/src/hooks/useWishlist.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { api } from '@/lib/api/client';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
interface WishlistItem {
|
||||
product_id: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
price: string;
|
||||
regular_price?: string;
|
||||
sale_price?: string;
|
||||
image?: string;
|
||||
on_sale?: boolean;
|
||||
stock_status?: string;
|
||||
type?: string;
|
||||
added_at: string;
|
||||
}
|
||||
|
||||
export function useWishlist() {
|
||||
const [items, setItems] = useState<WishlistItem[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [productIds, setProductIds] = useState<Set<number>>(new Set());
|
||||
|
||||
// Check if wishlist is enabled
|
||||
const isEnabled = (window as any).woonoowCustomer?.settings?.wishlist_enabled !== false;
|
||||
const isLoggedIn = (window as any).woonoowCustomer?.user?.isLoggedIn;
|
||||
|
||||
// Load wishlist on mount
|
||||
useEffect(() => {
|
||||
if (isEnabled && isLoggedIn) {
|
||||
loadWishlist();
|
||||
}
|
||||
}, [isEnabled, isLoggedIn]);
|
||||
|
||||
const loadWishlist = useCallback(async () => {
|
||||
if (!isLoggedIn) return;
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const data = await api.get<WishlistItem[]>('/account/wishlist');
|
||||
setItems(data);
|
||||
setProductIds(new Set(data.map(item => item.product_id)));
|
||||
} catch (error) {
|
||||
console.error('Failed to load wishlist:', error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [isLoggedIn]);
|
||||
|
||||
const addToWishlist = useCallback(async (productId: number) => {
|
||||
if (!isLoggedIn) {
|
||||
toast.error('Please login to add items to wishlist');
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
await api.post('/account/wishlist', { product_id: productId });
|
||||
await loadWishlist(); // Reload to get full product details
|
||||
toast.success('Added to wishlist');
|
||||
return true;
|
||||
} catch (error: any) {
|
||||
const message = error?.message || 'Failed to add to wishlist';
|
||||
toast.error(message);
|
||||
return false;
|
||||
}
|
||||
}, [isLoggedIn, loadWishlist]);
|
||||
|
||||
const removeFromWishlist = useCallback(async (productId: number) => {
|
||||
if (!isLoggedIn) return false;
|
||||
|
||||
try {
|
||||
await api.delete(`/account/wishlist/${productId}`);
|
||||
setItems(items.filter(item => item.product_id !== productId));
|
||||
setProductIds(prev => {
|
||||
const newSet = new Set(prev);
|
||||
newSet.delete(productId);
|
||||
return newSet;
|
||||
});
|
||||
toast.success('Removed from wishlist');
|
||||
return true;
|
||||
} catch (error) {
|
||||
toast.error('Failed to remove from wishlist');
|
||||
return false;
|
||||
}
|
||||
}, [isLoggedIn, items]);
|
||||
|
||||
const toggleWishlist = useCallback(async (productId: number) => {
|
||||
if (productIds.has(productId)) {
|
||||
return await removeFromWishlist(productId);
|
||||
} else {
|
||||
return await addToWishlist(productId);
|
||||
}
|
||||
}, [productIds, addToWishlist, removeFromWishlist]);
|
||||
|
||||
const isInWishlist = useCallback((productId: number) => {
|
||||
return productIds.has(productId);
|
||||
}, [productIds]);
|
||||
|
||||
return {
|
||||
items,
|
||||
isLoading,
|
||||
isEnabled,
|
||||
isLoggedIn,
|
||||
count: items.length,
|
||||
addToWishlist,
|
||||
removeFromWishlist,
|
||||
toggleWishlist,
|
||||
isInWishlist,
|
||||
refresh: loadWishlist,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user