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:
Bastian Masanek
2025-11-03 12:43:13 +01:00
parent 9d0e77fc98
commit b372e2cf78
44 changed files with 2209 additions and 123 deletions

View File

@@ -0,0 +1,100 @@
import { eq } from 'drizzle-orm'
import { products } from '../database/schema'
import type { H3Event } from 'h3'
/**
* Validate product availability for adding to cart
*
* Checks:
* - Product exists
* - Product is active
* - Product has sufficient stock
* - User has permission to view product (role-based visibility)
*
* @param event - H3 event object
* @param productId - Product UUID
* @param quantity - Requested quantity
* @returns Product details if valid
* @throws H3Error if validation fails
*/
export async function validateProductForCart(
event: H3Event,
productId: string,
quantity: number
) {
const db = useDatabase()
// Fetch product
const product = await db.query.products.findFirst({
where: eq(products.id, productId),
})
if (!product) {
throw createError({
statusCode: 404,
statusMessage: 'Product not found',
})
}
// Check if product is active
if (!product.active) {
throw createError({
statusCode: 400,
statusMessage: 'This product is no longer available',
})
}
// Check stock availability
if (product.stockQuantity < quantity) {
throw createError({
statusCode: 400,
statusMessage: `Insufficient stock. Only ${product.stockQuantity} available.`,
})
}
// Check role-based visibility
const { user } = await getUserSession(event)
if (!user) {
// Guest users cannot see products (MVP: no products visible to unauthenticated users)
throw createError({
statusCode: 403,
statusMessage: 'Please log in to add items to your cart',
})
}
// Check if user has permission to view this product
const canView = await isProductVisibleForUser(productId, user.id)
if (!canView) {
throw createError({
statusCode: 404,
statusMessage: 'Product not found',
})
}
return product
}
/**
* Validate quantity update for cart item
*
* @param newQuantity - New quantity value
* @param stockQuantity - Available stock
* @throws H3Error if validation fails
*/
export function validateQuantityUpdate(newQuantity: number, stockQuantity: number): void {
if (newQuantity < 1) {
throw createError({
statusCode: 400,
statusMessage: 'Quantity must be at least 1',
})
}
if (newQuantity > stockQuantity) {
throw createError({
statusCode: 400,
statusMessage: `Insufficient stock. Only ${stockQuantity} available.`,
})
}
}