- 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)
157 lines
4.6 KiB
Markdown
157 lines
4.6 KiB
Markdown
# Phase 4: Cart (Shopping Cart) ⚡ PRIORITY
|
|
|
|
**Status:** ✅ Done
|
|
**Progress:** 12/12 tasks (100%)
|
|
**Started:** 2025-11-03
|
|
**Completed:** 2025-11-03
|
|
**Assigned to:** Bastian
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
Implement shopping cart functionality: API endpoints for cart operations, cart composable, and UI components for cart display and management.
|
|
|
|
**Goal:** Users can add products to cart, update quantities, and remove items.
|
|
|
|
---
|
|
|
|
## Dependencies
|
|
|
|
- ✅ Phase 2: Database must be completed (carts, cart_items tables needed)
|
|
- ✅ Phase 3: Authentication should be completed (for user-specific carts)
|
|
- ⚠️ **Note:** Products can be seeded manually for testing (Phase 6 can be done after Cart)
|
|
|
|
---
|
|
|
|
## Tasks
|
|
|
|
### API Endpoints
|
|
|
|
- [x] Create /api/cart/index.get.ts endpoint
|
|
- Get current user's cart (or session cart for guests)
|
|
- Include cart items with product details (join)
|
|
- Calculate total price
|
|
- Return: { cart, items: [{product, quantity, subtotal}], total }
|
|
|
|
- [x] Create /api/cart/items.post.ts endpoint
|
|
- Add item to cart (body: {productId, quantity})
|
|
- Validate product exists and has stock
|
|
- Create cart if doesn't exist
|
|
- Upsert cart_item (update quantity if already exists)
|
|
- Return: Updated cart
|
|
|
|
- [x] Create /api/cart/items/[id].patch.ts endpoint
|
|
- Update cart item quantity (body: {quantity})
|
|
- Validate quantity > 0
|
|
- Validate stock availability
|
|
- Return: Updated cart item
|
|
|
|
- [x] Create /api/cart/items/[id].delete.ts endpoint
|
|
- Remove item from cart
|
|
- Delete cart_item record
|
|
- Return: 204 No Content
|
|
|
|
### Composables
|
|
|
|
- [x] Create useCart composable
|
|
- File: `composables/useCart.ts`
|
|
- State: cart (ref), items (computed), total (computed), itemCount (computed)
|
|
- Functions:
|
|
- `fetchCart()` - Load cart from API
|
|
- `addItem(productId, quantity)` - Add to cart
|
|
- `updateItem(itemId, quantity)` - Update quantity
|
|
- `removeItem(itemId)` - Remove from cart
|
|
- `clearCart()` - Empty cart
|
|
- Auto-fetch on mount
|
|
- See similar pattern: [CLAUDE.md: useAuth](../CLAUDE.md#oauth2-login-flow-pattern)
|
|
|
|
### UI Components
|
|
|
|
- [x] Create CartItem component
|
|
- File: `components/Cart/CartItem.vue`
|
|
- Props: item (object with product, quantity, subtotal)
|
|
- Display: Product image, name, price, quantity input, subtotal
|
|
- Actions: Update quantity, Remove button
|
|
- Emits: @update, @remove
|
|
|
|
- [x] Create CartSummary component
|
|
- File: `components/Cart/CartSummary.vue`
|
|
- Props: items (array), total (number)
|
|
- Display: Items count, subtotal, VAT, total
|
|
- Button: "Zur Kasse" (to checkout)
|
|
- Styling: shadcn-nuxt Card
|
|
|
|
### Pages
|
|
|
|
- [x] Create cart page
|
|
- File: `pages/warenkorb.vue` (German route)
|
|
- Uses: useCart composable
|
|
- Shows: List of CartItem components + CartSummary
|
|
- Empty state: "Ihr Warenkorb ist leer" with link to /produkte
|
|
- Loading state while fetching
|
|
|
|
### Testing
|
|
|
|
- [x] Test cart operations
|
|
- Add product to cart from product page
|
|
- Verify cart count updates (header badge)
|
|
- Visit /warenkorb page
|
|
- Update quantity via input
|
|
- Remove item via button
|
|
- Verify total updates correctly
|
|
|
|
- [x] Add cart persistence
|
|
- For logged-in users: cart stored in DB (user_id)
|
|
- For guests: cart stored in DB (session_id)
|
|
- Test cart persists across page reloads
|
|
- Test cart merges when guest logs in (optional, can defer)
|
|
|
|
- [x] Optimize cart queries
|
|
- Ensure product details are fetched efficiently (join, not N+1)
|
|
- Test with 10+ items in cart
|
|
- Add indexes if needed
|
|
|
|
- [x] Document cart logic
|
|
- Document cart/session relationship
|
|
- Document cart item uniqueness (cart_id + product_id)
|
|
- Document cart cleanup strategy (old carts)
|
|
|
|
---
|
|
|
|
## Acceptance Criteria
|
|
|
|
- [x] All 4 cart API endpoints work correctly
|
|
- [x] useCart composable manages cart state
|
|
- [x] CartItem component displays and allows editing
|
|
- [x] CartSummary component shows total correctly
|
|
- [x] /warenkorb page shows cart with all items
|
|
- [x] Can add products to cart from product pages
|
|
- [x] Can update item quantities in cart
|
|
- [x] Can remove items from cart
|
|
- [x] Cart total calculates correctly
|
|
- [x] Cart persists across page reloads
|
|
- [x] Empty cart shows helpful message
|
|
|
|
---
|
|
|
|
## Notes
|
|
|
|
- **Guest Carts:** Use session_id for guest carts (cookie-based)
|
|
- **Cart Merge:** When guest logs in, merge guest cart with user cart (optional for MVP)
|
|
- **Stock Validation:** Ensure quantity doesn't exceed stock when adding/updating
|
|
- **VAT:** 7% VAT for annual passes (hardcoded for MVP)
|
|
|
|
---
|
|
|
|
## Blockers
|
|
|
|
- None currently
|
|
|
|
---
|
|
|
|
## Related Documentation
|
|
|
|
- [docs/PRD.md: F-005](../docs/PRD.md#f-005-warenkorb)
|
|
- [docs/ARCHITECTURE.md: Carts Tables](../docs/ARCHITECTURE.md#carts)
|