Initial commit

This commit is contained in:
2026-03-07 11:07:45 -03:00
commit 9d523f8b6a
65 changed files with 17311 additions and 0 deletions

View File

@@ -0,0 +1,527 @@
# Product Detail Page Layout
## Contents
- [Overview](#overview)
- [Layout Structure](#layout-structure)
- [Price Display and Medusa Integration](#price-display-and-medusa-integration)
- [Variant Selection (Critical)](#variant-selection-critical)
- [Stock Availability](#stock-availability)
- [Add to Cart Behavior](#add-to-cart-behavior)
- [Product Details Organization](#product-details-organization)
- [Related Products Strategy](#related-products-strategy)
- [Trust Signals and Conversion](#trust-signals-and-conversion)
- [Mobile Optimization](#mobile-optimization)
- [Checklist](#checklist)
## Overview
Most critical page for conversion. Customers make purchase decisions here based on product information, images, reviews, and trust signals.
### Key Requirements
- High-quality product images with zoom capability
- Clear price display (handle variant price changes)
- Variant selection (size, color, material)
- Stock availability indicators
- Prominent "Add to Cart" with proper feedback
- Product details (description, specifications)
- Customer reviews and ratings
- Related product recommendations
- Trust signals (shipping, returns, secure checkout)
- Mobile-optimized (60%+ traffic)
### Routing Pattern
**CRITICAL: Always use dynamic routes, NEVER static pages.**
Product detail pages must use dynamic routes that accept a parameter (handle, slug, or ID):
**Correct examples:**
- Next.js App Router: `app/products/[handle]/page.tsx`
- Next.js Pages Router: `pages/products/[handle].tsx`
- SvelteKit: `routes/products/[handle]/+page.svelte`
- TanStack Start: `routes/products/$handle.tsx`
- Remix: `routes/products.$handle.tsx`
**Wrong examples:**
-`pages/products/blue-shirt.tsx` (static file per product)
-`pages/products/red-shoes.tsx` (doesn't scale)
Fetch product data in the dynamic route based on the handle/ID parameter from the URL.
## Layout Structure
**Desktop (two-column):**
- Left: Product images (50-60% width)
- Right: Product info, variants, add to cart (40-50%)
- Below: Product details, reviews, related products (full-width)
**Mobile (stacked):**
- Images at top (full-width, swipeable)
- Product info below (title, price, rating)
- Variants and add to cart
- Accordion for product details
- Reviews section
- Related products
- Sticky "Add to Cart" bar at bottom
**Sticky sidebar option (desktop):**
- Product info column stays visible during scroll
- Add to cart always accessible
- Useful for long product descriptions
- Improves conversion
## Price Display
### Standard Price Display
**Current price:**
- Large, bold font (28-36px)
- Currency symbol included ($49.99)
- Primary color or black
**Sale pricing:**
- Original price with strikethrough: ~~$79.99~~ $49.99
- Sale price in red or brand color
- "Save X%" badge nearby
- Example: Save 37%
**Variant price changes:**
- **When no variant selected**: Show "From $X" where X is the minimum variant price across all variants
- **When variant selected**: Update price dynamically to show the exact variant price
- No page reload required
- Show price change clearly (highlight briefly on change)
- Example: Product with variants priced at $29.99, $34.99, $39.99 → Show "From $29.99" initially
### Medusa Pricing (CRITICAL)
**Important difference from Stripe:**
- Medusa stores prices as-is (e.g., 49.99)
- Display directly: If API returns 49.99, show $49.99
- **DON'T divide by 100** (unlike Stripe which stores in cents)
- Example: Medusa 49.99 → Display $49.99 (NOT $0.4999)
**Multi-currency (Medusa):**
- Medusa supports multi-region pricing
- Display price in user's region currency
- Fetch pricing from selected region
- Show currency code (usd, eur, etc.)
## Variant Selection (Critical)
This is a complex ecommerce-specific challenge. Variants affect price, stock, and images.
### Variant Complexity
**Key challenges:**
- Multiple variant types (size, color, material)
- Variant availability varies (some sizes out of stock)
- Prices may differ by variant
- Images change by color variant
- Stock levels per variant
- Combinations may not exist (size M + color Red might not exist)
**Fetch from backend:**
```typescript
// Get all variants for product
// Change this based on the backend integrated
const product = await fetch(`/products/${id}?fields=*variants`)
// Returns variants with: id, sku, options, calculated_price, inventory_quantity
```
### Variant Selection Patterns
**Use Button Group when:**
- 2-8 options per variant type
- Size selection (XS, S, M, L, XL)
- Simple color options (5-6 colors)
- Users need to see all options at once
**Benefits:**
- Visible options (no click to reveal)
- Faster selection
- Clear visual feedback
- Better UX
**Use Dropdown when:**
- 10+ options per variant type
- Material/style options with long names
- Space-constrained layouts
- Mobile optimization needed
**Benefits:**
- Saves space
- Works better for many options
- Mobile-friendly
**Use Visual Swatches when:**
- Color or pattern variations
- Material with visual differences
- Visual is key to decision
- Fashion, home decor, customizable products
**Implementation:**
- Circular/square swatches (40-48px)
- Border on selected
- Show product image in that color when selected
- Color name on hover
- Gray out unavailable colors
### Variant Selection Flow
**Critical sequence:**
1. User selects first variant type (e.g., Color: Blue)
2. **Update available options** for other variant types
3. Show only size options available for Blue color
4. Gray out/disable unavailable combinations
5. Update price if variant price differs
6. Update main product image to show selected variant
7. Update stock availability
8. Enable/disable "Add to Cart" based on availability
**Example: Two variants (Color + Size)**
```typescript
// When color selected
// Change this based on the backend integrated
onColorSelect(color) {
// Find selected variant
const selectededVariant = product.variants.find((variant) => variant.options?.every(
(optionValue) => optionValue.id === selectedOptions[optionValue.option_id!]
))
// Check if size is selected and update price
if (selectededVariant) {
const variant = findVariant(color, selectedSize)
updatePrice(variant.price)
updateStock(variant.inventory_quantity)
}
}
```
### Validation and Error Handling
**Prevent adding without selection:**
- Disable "Add to Cart" until all required variants selected
- Or: Show error message "Please select a size"
- Highlight missing selection (red border around options)
- Scroll to variant selection on error
**Handle out of stock variants:**
- Gray out unavailable options
- "Out of stock" text on hover
- Don't allow selection of out of stock variants
- Suggest alternative variants if available
**Handle variant not found:**
- When combination doesn't exist (Size M + Color Red)
- Disable second option when first selected
- Show only valid combinations
- Or: Show "This combination is not available"
## Stock Availability
**Display patterns:**
**In stock:**
- Green indicator (✓ or dot)
- "In stock" or "Available"
- Quantity if low: "Only 3 left"
- Encourages urgency without being pushy
**Out of stock:**
- Red indicator (✗ or dot)
- "Out of stock" message
- Disable "Add to Cart" button (grayed out)
- Offer "Notify me when available"
- Email capture for restock notifications (if supported by backend)
**Low stock warning:**
- "Only X left in stock"
- Shows scarcity (increases urgency)
- Typically show when <= 5 items
- Orange/yellow color
**Pre-order:**
- "Pre-order now" status
- Expected availability date: "Ships on [Date]"
- Different button text: "Pre-order" instead of "Add to Cart"
- Charge now or later (specify)
**Backend integration:**
```typescript
// Fetch stock for selected variant
const stock = selectedVariant.inventory_quantity
if (stock === 0) {
showOutOfStock()
} else if (stock <= 5) {
showLowStock(stock) // "Only 3 left"
} else {
showInStock()
}
```
## Add to Cart Behavior
**Button states:**
- Default: Enabled (after variant selected)
- Hover: Slight color change or scale
- Loading: Spinner inside button (during API call)
- Success: Checkmark briefly, then revert
- Disabled: Grayed out (no variant or out of stock)
**Click behavior (Critical):**
1. Show loading state (disable button, show spinner)
2. Call API to add item to cart (backend)
3. **Optimistic UI**: Update cart count immediately (before API response)
4. Show success feedback (toast, checkmark, or cart popup)
5. Update cart count in navbar header
6. **DON'T navigate away** - stay on product page
7. Handle errors: restore count if API fails
**Success feedback options:**
- Toast notification: "Added to cart" (top-right)
- Cart popup: Show mini cart with items (see cart-popup.md)
- Checkmark in button briefly, then revert
- All three combined (checkmark + toast or cart popup)
**Error handling:**
```typescript
async function addToCart(variantId, quantity) {
try {
// Optimistic update
updateCartCountUI(+quantity)
// API call
// Change this based on the backend integrated
await fetch(`/store/carts/${cartId}/line-items`, {
method: 'POST',
body: JSON.stringify({ variant_id: variantId, quantity })
})
// Success feedback
showToast('Added to cart')
showCartPopup() // Optional
} catch (error) {
// Revert optimistic update
updateCartCountUI(-quantity)
// Show error
if (error.message === 'OUT_OF_STOCK') {
showError('Sorry, this item is now out of stock')
updateStockStatus('out_of_stock')
} else {
showError('Failed to add to cart. Please try again.')
}
}
}
```
**Buy Now button (optional):**
- Skip cart, go directly to checkout
- Useful for: high-value items, single-item stores, decisive customers
- Secondary button below "Add to Cart"
- Text: "Buy Now" or "Buy It Now"
- Add to cart + redirect to checkout in one action
## Product Details Organization
### Decision: Tabs vs Accordion
**Use Tabs (desktop) when:**
- 3-5 distinct sections
- Each section has substantial content
- Users may want to compare sections
- Desktop has screen space
- Examples: Description, Specifications, Shipping, Reviews
**Use Accordion (mobile) always:**
- Saves vertical space
- Users expand what they need
- Standard mobile pattern
- Collapses after reading
**Hybrid approach (recommended):**
- Tabs on desktop (horizontal navigation)
- Accordion on mobile (vertical expansion)
- Same content, different presentation
- Best of both worlds
### Common Sections
**Description:**
- Product overview (2-4 paragraphs)
- Key features (bullet points)
- Use cases
- Materials and craftsmanship
**Specifications:**
- Technical details (table format)
- Dimensions, weight, materials
- Care instructions
- Compatibility information
**Shipping & Returns:**
- Shipping options and costs
- Delivery timeframes
- Return policy (30 days, 60 days)
- Return process
- Link to full policy page
**Reviews:**
- Embedded in tab/accordion
- Or: Separate section below
- Filter by rating, sort by date
- Review submission form
## Related Products Strategy
**Types of recommendations:**
**"You May Also Like" (Similar products):**
- Same category, similar price point
- Algorithm: category match + price range
- Goal: Show alternatives if unsure about current product
**"Frequently Bought Together" (Complementary):**
- Products commonly purchased together
- Algorithm: order history analysis
- Goal: Increase average order value
- Example: Phone + Case + Screen Protector
- Show bundle discount if available
**"Recently Viewed" (Browsing history):**
- User's browsing history (session or logged-in)
- Helps users return to products they liked
- Goal: Reduce decision paralysis
**"Customers Also Viewed":**
- Products viewed by others who viewed this
- Algorithm: co-viewing patterns
- Goal: Discovery and alternatives
### Display Pattern
**Product slider:**
- 4-6 products visible (desktop)
- 2-3 visible (mobile)
- Horizontal scrolling (swipe on mobile)
- Product cards: image, title, price, rating
- Optional: Quick "Add to Cart" on hover
**Placement:**
- Below product details and reviews
- Above footer
- Full-width section
- Clear heading for each type
**Backend integration:**
```typescript
// Fetch recommendations
// Change this based on the backend integrated
const recommendations = await fetch(`/products/${id}/recommendations`)
// Returns: similar, bought_together, recently_viewed
```
## Trust Signals and Conversion
**Essential trust signals:**
**Near Add to Cart:**
- Free shipping badge (if applicable)
- Free returns icon + text
- Secure checkout icon
- Money-back guarantee
- Warranty information (if applicable)
**Below product title:**
- Customer rating and review count (4.8 ★ 324 reviews)
- Link to reviews section
- "Best seller" or "Top rated" badge
**Payment methods:**
- Accepted payment icons (Visa, Mastercard, PayPal, Apple Pay)
- Small icons (40px)
- Below "Add to Cart" or in footer
- Shows payment options available
**For new/unknown brands:**
- Customer testimonials
- "Join 10,000+ happy customers"
- Security badges (if legitimate - don't fake)
- Social proof (Instagram photos, user content)
- Clear contact information
**For high-value products:**
- Detailed specifications
- Professional photography
- Video demonstrations
- Warranty details prominently displayed
- Customer service contact visible
## Mobile Optimization
**Critical mobile patterns:**
**Sticky "Add to Cart" bar:**
- Fixed at bottom of screen
- Always accessible (no scrolling needed)
- Shows: Price + "Add to Cart" button
- Appears after scrolling past fold
- Higher conversion rates
**Image gallery:**
- Full-width swipeable carousel
- Pinch to zoom
- Dot indicators (1/5, 2/5)
- Tap to open full-screen view
**Variant selection:**
- Large touch targets (44-48px)
- Visual swatches easier than dropdowns
- Clear selected state
- Error messages visible
**Accordion for details:**
- Description, Specs, Shipping as accordion
- Starts collapsed (save space)
- User expands what they need
- Clear expand/collapse indicators
**Reviews section:**
- Expandable (start with 2-3 reviews)
- "Show more" button
- Filter by rating
- Star rating distribution chart
## Checklist
**Essential product detail page features:**
- [ ] High-quality product images with zoom
- [ ] Price displayed correctly (Medusa: use value as-is, not divided)
- [ ] Price shows "From $X" when no variant selected (X = minimum variant price)
- [ ] Variant selection required before adding to cart
- [ ] Variant selection updates: price, stock, image
- [ ] Disable unavailable variant options (gray out)
- [ ] Stock availability indicator (in stock, low stock, out of stock)
- [ ] "Only X left" shown when stock is low (<=5)
- [ ] Add to Cart disabled until variant selected
- [ ] Optimistic UI update (cart count updates immediately)
- [ ] Success feedback (toast, cart popup, or checkmark)
- [ ] Stay on product page after adding (don't navigate away)
- [ ] Error handling (out of stock, API failure)
- [ ] Product description and specifications
- [ ] Customer reviews and ratings
- [ ] Related products recommendations (similar, bought together)
- [ ] Trust signals (free shipping, returns, secure checkout)
- [ ] Payment method icons displayed
- [ ] Breadcrumb navigation
- [ ] Mobile: Swipeable image gallery
- [ ] Mobile: Accordion for product details
- [ ] Mobile: Sticky Add to Cart bar (optional but effective)
- [ ] Tabs on desktop, accordion on mobile (hybrid)
- [ ] Fast loading (<2s, optimize images)
- [ ] Keyboard accessible (tab through options, enter to add)
- [ ] ARIA labels on variant selection (role="group", aria-label)