Skip to main content

Offer Banner Architecture

This document explains the technical architecture and data flow of the ROfferBanner component.

Configuration Architecture

The component now uses a global singleton pattern for simplified configuration:

Global Singleton Configuration Flow

graph LR
A[reachu-config.json] --> B[ConfigurationLoader]
B --> C[ReachuConfiguration.shared]
C --> D[LiveShowConfiguration.campaignId]
D --> E[ComponentManager.shared]
E --> F[ROfferBannerDynamic]

style A fill:#e1f5fe
style B fill:#f3e5f5
style C fill:#e8f5e8
style D fill:#fff3e0
style E fill:#fff3e0
style F fill:#e1f5fe

Singleton Benefits

Global Singleton Pattern: - Zero Configuration - No parameters needed anywhere

  • Global Access - Available from any view with ComponentManager.shared
  • Centralized Management - All configuration in one file
  • Consistent Behavior - Same campaign ID across the entire app
  • Easy Updates - Change campaign ID without code changes
  • Auto-Connection - Automatically connects on app startup
  • Reduced Errors - No risk of passing wrong campaign ID
  • Simplified Integration - Just use ROfferBannerDynamic() anywhere

Component Architecture

graph TB
subgraph "iOS App"
A[ROfferBannerDynamic] --> B[ComponentManager]
B --> C[ROfferBanner]
C --> D[CountdownView]
C --> E[AsyncImage]
C --> F[CTA Button]
end

subgraph "Backend Services"
G[REST API] --> H[Active Components]
I[WebSocket Server] --> J[Real-time Updates]
end

subgraph "Data Flow"
K[Campaign ID] --> B
B --> L[API Call]
L --> G
G --> M[Component Config]
M --> B
B --> N[Published State]
N --> C
C --> O[UI Rendering]

P[WebSocket Connection] --> B
B --> I
I --> Q[Status Updates]
Q --> B
B --> R[State Update]
R --> N
end

style A fill:#e1f5fe
style B fill:#f3e5f5
style C fill:#e8f5e8
style G fill:#fff3e0
style I fill:#fff3e0

Data Flow Diagram

sequenceDiagram
participant App as iOS App
participant Manager as ComponentManager.shared
participant API as REST API
participant WS as WebSocket
participant Banner as ROfferBanner

App->>Manager: Access ComponentManager.shared
Manager->>Manager: Auto-initialize with config campaignId
Manager->>Manager: Auto-connect()

Manager->>API: GET /api/campaigns/{id}/active-components
API-->>Manager: Active Components Response

Manager->>WS: Connect to WebSocket
WS-->>Manager: Connection Established

Manager->>Banner: Update activeBanner state
Banner->>Banner: Render banner with config

Note over Banner: Banner displays with skeleton loading

Banner->>Banner: Load images asynchronously
Banner->>Banner: Start countdown timer

Note over WS: Real-time updates
WS->>Manager: Component status changed
Manager->>Banner: Update configuration
Banner->>Banner: Re-render with new config

Note over WS: Campaign ends
WS->>Manager: Campaign ended
Manager->>Banner: Clear activeBanner
Banner->>Banner: Hide banner

Note over Manager: Global singleton manages lifecycle automatically
Manager->>Manager: Auto-cleanup resources

Component Hierarchy

graph TD
A[ROfferBannerContainer] --> B[ComponentManager]
A --> C[ROfferBanner]

B --> D[WebSocketManager]
B --> E[API Client]
B --> F[State Management]

C --> G[Background Layer]
C --> H[Content Layer]
C --> I[Overlay Layer]

G --> J[AsyncImage - Background]
H --> K[Logo]
H --> L[Title & Subtitle]
H --> M[CountdownView]
H --> N[Discount Badge]
H --> O[CTA Button]
I --> P[Dark Overlay]

M --> Q[TimeUnit Components]

style A fill:#e1f5fe
style B fill:#f3e5f5
style C fill:#e8f5e8
style D fill:#fff3e0
style E fill:#fff3e0

State Management

stateDiagram-v2
[*] --> Initializing
Initializing --> Connecting
Connecting --> Connected
Connecting --> Failed

Connected --> FetchingComponents
FetchingComponents --> ComponentsLoaded
FetchingComponents --> FetchFailed

ComponentsLoaded --> BannerActive
ComponentsLoaded --> NoBanner

BannerActive --> BannerInactive
BannerInactive --> BannerActive

BannerActive --> CampaignEnded
BannerInactive --> CampaignEnded
NoBanner --> CampaignEnded

CampaignEnded --> [*]
Failed --> [*]
FetchFailed --> [*]

note right of BannerActive
Banner is visible with
countdown timer running
end note

note right of BannerInactive
Banner is hidden but
connection remains active
end note

Error Handling Flow

flowchart TD
A[Component Initialization] --> B{API Available?}
B -->|Yes| C[Fetch Components]
B -->|No| D[Show Error State]

C --> E{Components Found?}
E -->|Yes| F[Display Banner]
E -->|No| G[Show Empty State]

F --> H{WebSocket Connected?}
H -->|Yes| I[Listen for Updates]
H -->|No| J[Retry Connection]

I --> K{Update Received?}
K -->|Yes| L[Update Banner]
K -->|No| M[Maintain Current State]

J --> N{Max Retries?}
N -->|No| H
N -->|Yes| O[Fallback to Static State]

L --> P{Valid Config?}
P -->|Yes| Q[Render New Banner]
P -->|No| R[Log Error & Keep Current]

style D fill:#ffebee
style G fill:#fff3e0
style O fill:#fff3e0
style R fill:#ffebee

Performance Considerations

Memory Management

  • Automatic cleanupof WebSocket connections
  • Timer invalidationon component disposal
  • Image cachingfor frequently used assets
  • State observationcleanup in deinit

Network Optimization

  • Exponential backofffor failed connections
  • Connection poolingfor API requests
  • Compressed WebSocket messages - Efficient state updatesto minimize re-renders

UI Performance

  • Lazy loadingof images
  • Skeleton statesto prevent layout jumps
  • Efficient countdown updates(1-second intervals)
  • Minimal re-rendersthrough proper state management

Security Considerations

  • HTTPS/WSSconnections only
  • API key validationon backend
  • Input sanitizationfor all configuration data
  • XSS preventionin dynamic content
  • Secure image loadingwith URL validation

Scalability Features

  • Multiple campaign supportthrough different IDs
  • Horizontal scalingvia load balancers
  • Caching layersfor frequently accessed data
  • Rate limitingto prevent abuse
  • Graceful degradationunder high load