Files
my2/app/composables/useCart.ts
Bastian Masanek b372e2cf78 Implement shopping cart functionality with UI components and API integration
- Added CartItem, CartSummary, CartEmpty, CartSidebar, and CartSheet components for managing cart display and interactions.
- Integrated useCart and useCartUI composables for cart state management and UI control.
- Implemented API endpoints for cart operations, including fetching, adding, updating, and removing items.
- Enhanced user experience with loading states and notifications using vue-sonner for cart actions.
- Configured session management for guest and authenticated users, ensuring cart persistence across sessions.

This commit completes the shopping cart feature, enabling users to add items, view their cart, and proceed to checkout.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2025-11-03 12:43:13 +01:00

179 lines
4.1 KiB
TypeScript

// 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,
}
}