Skip to main content

RProductDetailOverlay

A comprehensive, full-screen modal overlay that displays detailed product information with an elegant image gallery, variant selection, quantity controls, and integrated cart functionality.

Overview

The RProductDetailOverlay provides a complete product detail experience that appears as a modal sheet over your app. It's designed to work seamlessly with the existing RProductCard component and automatically integrates with the global cart system.

Key Features

  • Advanced Image Gallery - Swipeable main images with thumbnail navigation
  • Variant Selection - Interactive variant picker with stock validation
  • Quantity Controls - Smart quantity selector with stock limits
  • Product Information - Complete product details and specifications
  • Cart Integration - Seamless add-to-cart with animations and feedback
  • Cross-Platform - Works on iOS, macOS, tvOS, and watchOS
  • Automatic Integration - Works out-of-the-box with RProductCard

Automatic Integration

Zero Configuration Required

The overlay automatically appears when users tap on any RProductCard:

// This automatically shows product detail overlay on tap
RProductCard(product: product, variant: .grid)

What happens automatically:

  1. User taps any RProductCard
  2. RProductDetailOverlay opens as a modal sheet
  3. Shows complete product information
  4. User can add to cart directly from overlay
  5. Animations and notifications work seamlessly

Disable Automatic Overlay

If you prefer custom tap handling:

RProductCard(
product: product,
variant: .grid,
showProductDetail: false, // Disables automatic overlay
onTap: {
// Your custom tap action
print("Custom tap handling")
}
)

Manual Usage

Direct Implementation

You can also use the overlay directly:

import SwiftUI
import ReachuUI

struct ProductDetailExample: View {
@State private var selectedProduct: Product?
@EnvironmentObject var cartManager: CartManager

var body: some View {
Button("Show Product Details") {
selectedProduct = sampleProduct
}
.sheet(item: $selectedProduct) { product in
RProductDetailOverlay(product: product)
.environmentObject(cartManager)
}
}
}

Custom Callbacks

Add custom actions for product interactions:

RProductDetailOverlay(
product: product,
onDismiss: {
print("Overlay dismissed")
},
onAddToCart: { product in
print("Added \(product.title) to cart")
// Custom analytics tracking
analytics.track("product_added_to_cart", product: product)
}
)
.environmentObject(cartManager)

Multiple Image Support

The overlay automatically handles products with multiple images:

// Product with multiple images
let product = Product(
id: 1,
title: "Sample Product",
images: [
ProductImage(id: "1", url: "image1.jpg", order: 0), // Primary
ProductImage(id: "2", url: "image2.jpg", order: 1), // Secondary
ProductImage(id: "3", url: "image3.jpg", order: 2), // Additional
]
// ... other properties
)

Gallery Features:

  • Main Image Display - Large, swipeable image viewer
  • Thumbnail Navigation - Horizontal scrolling thumbnail gallery
  • Smart Ordering - Automatically sorts by order field
  • Touch Navigation - Tap thumbnails to switch main image
  • Loading States - Progressive loading with placeholders
  • Error Handling - Fallback icons for broken images

Single Image Optimization

For products with one image, the gallery simplifies automatically:

// Single image - no thumbnails shown
let singleImageProduct = Product(
id: 1,
title: "Single Image Product",
images: [
ProductImage(id: "1", url: "single-image.jpg", order: 0)
]
)

No Images Fallback

Graceful handling when no images are available:

// No images - shows placeholder
let noImageProduct = Product(
id: 1,
title: "Text Only Product",
images: [] // Empty array
)

Variant Selection

Interactive Variant Picker

When products have variants, an interactive selector appears:

let productWithVariants = Product(
id: 1,
title: "T-Shirt",
variants: [
Variant(id: "small", title: "Small", quantity: 10),
Variant(id: "medium", title: "Medium", quantity: 5),
Variant(id: "large", title: "Large", quantity: 0), // Out of stock
]
)

Variant Features:

  • Visual Selection - Clear active/inactive states
  • Stock Validation - Disabled variants show as unavailable
  • Price Updates - Price changes based on selected variant
  • Horizontal Scrolling - Handles many variants gracefully

No Variants Handling

Products without variants work seamlessly:

// No variants - selector doesn't appear
let simpleProduct = Product(
id: 1,
title: "Simple Product",
variants: [] // No variants
)

Quantity Selection

Smart Quantity Controls

The quantity selector includes intelligent stock validation:

// Quantity controls automatically respect stock limits
let limitedStockProduct = Product(
id: 1,
title: "Limited Item",
quantity: 3, // Only 3 in stock
variants: [
Variant(id: "v1", title: "Variant 1", quantity: 2), // Max 2 for this variant
]
)

Quantity Features:

  • Stock Limits - Cannot exceed available quantity
  • Variant-Aware - Limits based on selected variant
  • Visual Feedback - Disabled states when at limits
  • Dynamic Pricing - Total price updates in real-time

Quantity Controls Layout

// Layout: [−] [2] [+] | Total: $19.98
//
// - Decrease button (disabled at quantity 1)
// - Current quantity display
// - Increase button (disabled at stock limit)
// - Real-time total price calculation

Product Information Display

Complete Product Details

The overlay shows comprehensive product information:

// All product fields are displayed when available
let detailedProduct = Product(
id: 1,
title: "Wireless Headphones",
brand: "Reachu Audio",
description: "Premium noise-cancelling wireless headphones...",
sku: "RCH-HP-001",
supplier: "Reachu Electronics",
categories: [
Category(id: 1, name: "Electronics"),
Category(id: 5, name: "Audio")
]
)

Information Sections:

  1. Header - Title, brand, price, stock status
  2. Description - Full product description (expandable)
  3. Specifications - SKU, categories, supplier, stock count
  4. Pricing - Current price, compare-at price if available

Optional Field Handling

The overlay gracefully handles missing information:

// Missing fields are automatically hidden
let minimalProduct = Product(
id: 1,
title: "Basic Product",
brand: nil, // Won't show brand section
description: nil, // Won't show description section
categories: nil // Won't show categories in specs
)

Cart Integration

Seamless Cart Operations

The overlay integrates perfectly with the global cart system:

struct AppWithCart: View {
@StateObject private var cartManager = CartManager()

var body: some View {
ProductCatalogView()
.environmentObject(cartManager)
// RProductDetailOverlay automatically uses cartManager
}
}

Cart Features:

  • Automatic Integration - No setup required
  • Quantity Support - Adds selected quantity to cart
  • Variant Handling - Includes selected variant information
  • Animation Feedback - Button animations and state changes
  • Toast Notifications - Automatic "Added to cart" messages
  • Haptic Feedback - Tactile confirmation on iOS

Add to Cart Animation Sequence

When user taps "Add to Cart":

// Automatic animation sequence:
1. Button scales down (0.95x) - 0.1s
2. Shows loading spinner - variable duration
3. Shows "Added!" with checkmark - 1.5s
4. Returns to normal state - 0.3s
5. Toast notification appears
6. Haptic feedback (iOS)
7. Cart indicator updates

Advanced Customization

Custom Overlay Configuration

// Advanced configuration example
struct CustomProductDetail: View {
@State private var selectedProduct: Product?
@EnvironmentObject var cartManager: CartManager

var body: some View {
ProductGrid()
.sheet(item: $selectedProduct) { product in
RProductDetailOverlay(
product: product,
onDismiss: {
// Custom dismiss handling
Analytics.track("product_detail_closed")
},
onAddToCart: { product in
// Custom add to cart handling
Analytics.track("product_added_from_detail", product: product)

// Still add to cart normally
Task {
await cartManager.addProduct(product)
}
}
)
.environmentObject(cartManager)
}
}
}

Integration with Navigation

// Deep linking support
struct ProductDetailDeepLink: View {
let productId: Int
@State private var product: Product?
@State private var showingDetail = false

var body: some View {
EmptyView()
.onAppear {
loadProduct()
}
.sheet(isPresented: $showingDetail) {
if let product = product {
RProductDetailOverlay(product: product)
.environmentObject(CartManager())
}
}
}

private func loadProduct() {
// Load product by ID and show overlay
Task {
self.product = try await Reachu.shared.products.getProduct(id: "\(productId)")
self.showingDetail = true
}
}
}

Cross-Platform Considerations

iOS Specific Features

#if os(iOS)
// iOS-specific features automatically enabled:
- Full haptic feedback support
- Large navigation title display
- Page tab view style for image gallery
- Dynamic Type support
- Swipe gesture navigation
#endif

macOS Adaptations

#if os(macOS)
// macOS adaptations automatically applied:
- No haptic feedback (not available)
- Standard navigation title
- Alternative image navigation
- Keyboard navigation support
- Mouse hover states
#endif

tvOS Optimizations

#if os(tvOS)
// tvOS optimizations:
- Focus management compatible
- Remote control navigation
- Appropriate sizing for TV screens
- Simplified interaction model
#endif

watchOS Simplifications

#if os(watchOS)
// watchOS simplifications:
- Condensed information display
- Essential actions only
- Watch-appropriate haptic patterns
- Optimized for small screens
#endif

Performance Considerations

Image Loading Optimization

  • Lazy Loading - Images load only when visible
  • Progressive Enhancement - Placeholder → Image → Error states
  • Memory Management - Automatic image disposal
  • Cache Integration - Uses AsyncImage built-in caching

Rendering Performance

  • Conditional Rendering - Sections appear only when data exists
  • Efficient Updates - Minimal re-renders on state changes
  • Animation Optimization - Hardware-accelerated animations
  • State Management - Proper use of @State and @EnvironmentObject

Accessibility Features

Comprehensive Accessibility

The overlay includes full accessibility support:

// Automatic accessibility features:
- Screen reader support for all elements
- Keyboard navigation (macOS)
- Dynamic Type support (iOS)
- High contrast compatibility
- Reduced motion respect
- Voice Control support (iOS)

Custom Accessibility Labels

// Accessibility labels are automatically generated:
.accessibilityLabel("Product: \(product.title), Price: \(product.price.displayAmount)")
.accessibilityHint("Tap to add to cart")
.accessibilityValue("In stock: \(product.quantity) available")

Common Use Cases

E-commerce Apps

Perfect for traditional e-commerce applications:

// Product catalog with detail overlay
LazyVGrid(columns: gridColumns) {
ForEach(products) { product in
RProductCard(product: product, variant: .grid)
// Automatically shows RProductDetailOverlay on tap
}
}

Marketplace Apps

Ideal for marketplace-style applications:

// Featured products with detailed views
RProductSlider(
title: "Featured Products",
products: featuredProducts,
layout: .featured,
onProductTap: { product in
// Product detail overlay opens automatically
Analytics.track("featured_product_viewed", product: product)
}
)

Content Apps with Shopping

Great for content apps with integrated shopping:

// Blog post with embedded products
VStack {
ArticleContent()

VStack(alignment: .leading) {
Text("Featured Products")
.font(.headline)

LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible())]) {
ForEach(relatedProducts) { product in
RProductCard(product: product, variant: .grid)
// Detail overlay maintains content context
}
}
}
}

Social Commerce

Perfect for social commerce integrations:

// Social post with product tags
ZStack {
PostImage()

// Product hotspots
ForEach(taggedProducts) { product in
ProductHotspot(product: product) {
// Shows product detail without leaving post
selectedProduct = product
}
}
}
.sheet(item: $selectedProduct) { product in
RProductDetailOverlay(product: product)
.environmentObject(cartManager)
}

Best Practices

Integration Guidelines

  1. Environment Objects - Always provide CartManager as environment object
  2. Error Handling - Handle network errors in product loading
  3. Loading States - Show appropriate loading indicators
  4. Analytics - Track product detail views and interactions
  5. Performance - Use lazy loading for product lists

Design Considerations

  1. Information Hierarchy - Most important info appears first
  2. Visual Consistency - Matches your app's design system
  3. User Flow - Easy path from viewing to purchasing
  4. Cross-Platform - Works consistently across all platforms
  5. Accessibility - Full support for assistive technologies

Development Tips

  1. Mock Data - Use MockDataProvider for development
  2. Preview Support - Leverage SwiftUI Previews for rapid iteration
  3. Modular Testing - Test individual components separately
  4. State Management - Keep state minimal and focused
  5. Error Boundaries - Gracefully handle missing or invalid data

Automatic Integration

The RProductDetailOverlay works automatically with RProductCard components. Simply ensure your app has a CartManager environment object, and product details will appear when users tap any product card.

Custom Implementation

While the overlay integrates automatically, you can also implement it manually for custom use cases like deep linking, programmatic display, or integration with non-Reachu product data sources.

Environment Object Required

The overlay requires a CartManager environment object to function properly. Make sure to provide this at your app's root level or at the level where the overlay is presented.