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:
- User taps any
RProductCard
RProductDetailOverlay
opens as a modal sheet- Shows complete product information
- User can add to cart directly from overlay
- 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)
Image Gallery Features
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:
- Header - Title, brand, price, stock status
- Description - Full product description (expandable)
- Specifications - SKU, categories, supplier, stock count
- 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
- Environment Objects - Always provide
CartManager
as environment object - Error Handling - Handle network errors in product loading
- Loading States - Show appropriate loading indicators
- Analytics - Track product detail views and interactions
- Performance - Use lazy loading for product lists
Design Considerations
- Information Hierarchy - Most important info appears first
- Visual Consistency - Matches your app's design system
- User Flow - Easy path from viewing to purchasing
- Cross-Platform - Works consistently across all platforms
- Accessibility - Full support for assistive technologies
Development Tips
- Mock Data - Use
MockDataProvider
for development - Preview Support - Leverage SwiftUI Previews for rapid iteration
- Modular Testing - Test individual components separately
- State Management - Keep state minimal and focused
- Error Boundaries - Gracefully handle missing or invalid data
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.
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.
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.