You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

178 lines
4.1 KiB

// composables/useCart.ts
import type { CartSummary } from '~/types/cart'
/**
* Shopping Cart composable
*
* Manages cart state and provides methods for cart operations
*
* Features:
* - Reactive cart state (cart, items, total, itemCount)
* - Auto-fetch cart on mount
* - Add, update, and remove items
* - Loading states for async operations
* - Error handling with notifications for removed items
*
* Usage:
* const { cart, items, total, itemCount, loading, addItem, updateItem, removeItem, fetchCart } = useCart()
*/
// Global cart state (shared across all components)
const cartState = ref<CartSummary | null>(null)
const loading = ref(false)
const initialized = ref(false)
export function useCart() {
// Computed reactive properties
const cart = computed(() => cartState.value?.cart ?? null)
const items = computed(() => cartState.value?.items ?? [])
const total = computed(() => cartState.value?.total ?? 0)
const itemCount = computed(() => cartState.value?.itemCount ?? 0)
/**
* Fetch cart from server
* Auto-cleans unavailable products and returns removed items
*/
async function fetchCart() {
loading.value = true
try {
const data = await $fetch<CartSummary>('/api/cart', {
method: 'GET',
})
cartState.value = data
// Show notification if products were removed
if (data.removedItems && data.removedItems.length > 0) {
// TODO: Show toast notification when toast composable is implemented
// For now, log to console
console.warn('Products removed from cart:', data.removedItems)
}
return data
} catch (error) {
console.error('Failed to fetch cart:', error)
// Set to null on error
cartState.value = null
throw error
} finally {
loading.value = false
}
}
/**
* Add item to cart
*
* @param productId - Product UUID
* @param quantity - Quantity to add (default: 1)
*/
async function addItem(productId: string, quantity: number = 1) {
loading.value = true
try {
await $fetch('/api/cart/items', {
method: 'POST',
body: {
productId,
quantity,
},
})
// Refresh cart to get updated state
await fetchCart()
} catch (error) {
console.error('Failed to add item to cart:', error)
throw error
} finally {
loading.value = false
}
}
/**
* Update cart item quantity
*
* @param itemId - Cart item UUID
* @param quantity - New quantity (must be >= 1)
*/
async function updateItem(itemId: string, quantity: number) {
if (quantity < 1) {
throw new Error('Quantity must be at least 1')
}
loading.value = true
try {
await $fetch(`/api/cart/items/${itemId}`, {
method: 'PATCH',
body: {
quantity,
},
})
// Refresh cart to get updated state
await fetchCart()
} catch (error) {
console.error('Failed to update cart item:', error)
throw error
} finally {
loading.value = false
}
}
/**
* Remove item from cart
*
* @param itemId - Cart item UUID
*/
async function removeItem(itemId: string) {
loading.value = true
try {
await $fetch(`/api/cart/items/${itemId}`, {
method: 'DELETE',
})
// Refresh cart to get updated state
await fetchCart()
} catch (error) {
console.error('Failed to remove cart item:', error)
throw error
} finally {
loading.value = false
}
}
/**
* Clear all items from cart
* For future use (not implemented in API yet)
*/
async function clearCart() {
// TODO: Implement when API endpoint is ready
console.warn('clearCart() not yet implemented')
}
/**
* Initialize cart on mount
* Only fetches once per session
*/
onMounted(async () => {
if (!initialized.value) {
await fetchCart()
initialized.value = true
}
})
return {
// State
cart,
items,
total,
itemCount,
loading,
// Methods
fetchCart,
addItem,
updateItem,
removeItem,
clearCart,
}
}