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)
This commit is contained in:
104
app/composables/useCartUI.ts
Normal file
104
app/composables/useCartUI.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
// composables/useCartUI.ts
|
||||
|
||||
import { useMediaQuery } from '@vueuse/core'
|
||||
|
||||
/**
|
||||
* Cart UI composable
|
||||
*
|
||||
* Manages cart sidebar/sheet UI state and responsive behavior
|
||||
*
|
||||
* Features:
|
||||
* - Sidebar/sheet open/close state
|
||||
* - Responsive detection (mobile vs desktop)
|
||||
* - Body scroll lock when cart is open
|
||||
* - Global state (shared across all components)
|
||||
*
|
||||
* Usage:
|
||||
* const { isOpen, isMobile, open, close, toggle } = useCartUI()
|
||||
*/
|
||||
|
||||
// Global cart UI state (shared across all components)
|
||||
const isOpen = ref(false)
|
||||
|
||||
export function useCartUI() {
|
||||
// Responsive breakpoint: mobile = width < 1024px (lg breakpoint)
|
||||
const isMobile = useMediaQuery('(max-width: 1023px)')
|
||||
|
||||
/**
|
||||
* Open cart sidebar/sheet
|
||||
*/
|
||||
function open() {
|
||||
isOpen.value = true
|
||||
lockBodyScroll()
|
||||
}
|
||||
|
||||
/**
|
||||
* Close cart sidebar/sheet
|
||||
*/
|
||||
function close() {
|
||||
isOpen.value = false
|
||||
unlockBodyScroll()
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle cart sidebar/sheet
|
||||
*/
|
||||
function toggle() {
|
||||
if (isOpen.value) {
|
||||
close()
|
||||
} else {
|
||||
open()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock body scroll (prevent scrolling when cart is open)
|
||||
*/
|
||||
function lockBodyScroll() {
|
||||
if (import.meta.client) {
|
||||
document.body.style.overflow = 'hidden'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock body scroll
|
||||
*/
|
||||
function unlockBodyScroll() {
|
||||
if (import.meta.client) {
|
||||
document.body.style.overflow = ''
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up: Ensure body scroll is unlocked when component unmounts
|
||||
*/
|
||||
onUnmounted(() => {
|
||||
unlockBodyScroll()
|
||||
})
|
||||
|
||||
/**
|
||||
* Watch for route changes: Close cart when navigating
|
||||
*/
|
||||
if (import.meta.client) {
|
||||
const route = useRoute()
|
||||
watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
if (isOpen.value) {
|
||||
close()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
// State
|
||||
isOpen: readonly(isOpen),
|
||||
isMobile: readonly(isMobile),
|
||||
|
||||
// Methods
|
||||
open,
|
||||
close,
|
||||
toggle,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user