skills/flutterflow-designer/screen-blueprints.md

34 KiB
Raw Permalink Blame History

ZIVVO Screen Blueprints

Screen-by-screen widget trees and build guides for all 4 roles. Each blueprint shows the exact widget hierarchy and key properties to configure in FlutterFlow.

How to Use These Blueprints

  1. Create a new page in FlutterFlow
  2. Follow the widget tree top-down — add outermost widget first
  3. Indented items are children of the item above
  4. Properties in parentheses are the key values to set
  5. After building, preview on target device size (390x844 for mobile)

Shared Screens (All Roles)

Splash Screen

Page settings: No AppBar, no bottom nav, full screen, no scroll.

Scaffold (backgroundColor: Background #FAFAF7)
└── Stack
    ├── Container (width: Expand, height: Expand)
    │   └── Gradient background: Sunrise (Primary Light 8% → transparent)
    ├── Center
    │   └── Column (mainAxisAlignment: Center, crossAxisSize: Min)
    │       ├── Image (src: ZIVVO logo asset, width: 120, height: 120)
    │       ├── SizedBox (height: 16)
    │       └── Text ("ZIVVO", style: displayLarge, color: Primary #D4A012)
    └── Positioned (bottom: 48, left: 0, right: 0)
        └── Center
            └── CircularProgressIndicator (color: Secondary #0D8B7D, strokeWidth: 3)

Build steps:

1. Create page "SplashScreen" → set as home page
2. Disable AppBar and bottom nav in page settings
3. Add Stack as root widget
4. Inside Stack: add Container → set Expand width/height → add gradient
5. Inside Stack: add Center → Column → Image + SizedBox + Text
6. Inside Stack: add Align (bottom center) → CircularProgressIndicator
7. Actions → On Load: wait 2s then navigate to OnboardingPage

Onboarding (3 Pages)

Page settings: No AppBar, no bottom nav, full screen.

Scaffold
└── Column (mainAxisAlignment: SpaceBetween)
    ├── Expanded
    │   └── PageView (controller: pageController, pageSnapping: true)
    │       ├── Page 1: "Move Freely"
    │       │   └── Column (mainAxisAlignment: Center, padding: 32)
    │       │       ├── Image (src: city illustration, width: 280, height: 280, fit: Contain)
    │       │       ├── SizedBox (height: 32)
    │       │       ├── Text ("Move Freely", style: headlineLarge, textAlign: Center)
    │       │       ├── SizedBox (height: 12)
    │       │       └── Text ("Rides, rentals, and deliveries — all in one app.",
    │       │              style: bodyLarge, color: TextSecondary, textAlign: Center)
    │       ├── Page 2: "Works Everywhere"
    │       │   └── Column (same structure)
    │       │       ├── Image (signal bars illustration)
    │       │       ├── Text ("Works Everywhere")
    │       │       └── Text ("Offline maps, low-bandwidth tracking, 2G-ready.")
    │       └── Page 3: "You're in Control"
    │           └── Column (same structure)
    │               ├── Image (tracking screen illustration)
    │               ├── Text ("You're in Control")
    │               └── Text ("Real-time tracking, transparent pricing, SOS safety.")
    ├── Container (padding: horizontal 24, vertical 16)
    │   └── Column
    │       ├── Row (mainAxisAlignment: Center, spacing: 8)
    │       │   ├── Container (w: 8, h: 8, radius: 4, color: conditional on page index)
    │       │   ├── Container (same — dot indicator)
    │       │   └── Container (same — dot indicator)
    │       ├── SizedBox (height: 24)
    │       └── Row (mainAxisAlignment: SpaceBetween)
    │           ├── ZivvoButtonGhost (text: "Skip", onTap: navigate to PhoneEntry)
    │           └── ZivvoButtonPrimary (text: conditional "Next"/"Get Started",
    │                  width: 160, onTap: next page or navigate to PhoneEntry)

Phone Entry Screen

Scaffold (AppBar: back button only, transparent, no title)
└── Column (padding: horizontal 24)
    ├── SizedBox (height: 32)
    ├── Text ("Enter your phone number", style: headlineLarge)
    ├── SizedBox (height: 8)
    ├── Text ("We'll send you a verification code",
    │        style: bodyMedium, color: TextSecondary)
    ├── SizedBox (height: 32)
    ├── Row (spacing: 12)
    │   ├── Container (width: 88, height: 52, radius: 12, border: 1.5px #E8E4DC)
    │   │   └── Center
    │   │       └── Row (mainAxisAlignment: Center, spacing: 4)
    │   │           ├── Text ("🇨🇲", style: bodyLarge)
    │   │           └── Text ("+237", style: bodyLarge, weight: 600)
    │   └── Expanded
    │       └── ZivvoInput (hintText: "6XX XXX XXX", keyboardType: Phone,
    │              maxLength: 9, autofocus: true)
    ├── Spacer
    └── Container (padding: bottom 32)
        └── ZivvoButtonPrimary (text: "Continue", width: Expand,
               enabled: phoneField.length == 9,
               onTap: send OTP → navigate to OTPVerification)

OTP Verification Screen

Scaffold (AppBar: back button, transparent)
└── Column (padding: horizontal 24)
    ├── SizedBox (height: 32)
    ├── Text ("Verify your number", style: headlineLarge)
    ├── SizedBox (height: 8)
    ├── RichText
    │   ├── TextSpan ("We sent a code to ", style: bodyMedium, color: TextSecondary)
    │   └── TextSpan ("+237 6XX XXX XXX", style: bodyMedium, weight: 600)
    ├── SizedBox (height: 40)
    ├── PinCode (length: 6, autoFocus: true, keyboardType: Number,
    │          fieldWidth: 48, fieldHeight: 56, borderRadius: 12,
    │          activeBorderColor: Primary, selectedBorderColor: Secondary)
    ├── SizedBox (height: 24)
    ├── Row (mainAxisAlignment: Center)
    │   ├── Text ("Didn't receive code? ", style: bodySmall, color: TextSecondary)
    │   └── TextButton ("Resend", style: labelLarge, color: Secondary,
    │          enabled: resendTimer == 0, onTap: resend OTP)
    ├── Spacer
    └── Container (padding: bottom 32)
        └── ZivvoButtonPrimary (text: "Verify", width: Expand,
               enabled: pinCode.length == 6,
               onTap: verify OTP → navigate based on registration state)

Settings Screen

Scaffold (AppBar: title "Settings", back button)
└── ListView (padding: vertical 8)
    ├── ListTile (leading: CircleImage(user photo), title: user name,
    │          subtitle: phone number, trailing: chevron, onTap: Profile)
    ├── Divider (indent: 16, endIndent: 16)
    ├── SectionHeader ("Preferences")
    ├── ListTile (leading: Icon(language), title: "Language",
    │          trailing: Text(current lang), onTap: LanguagePicker)
    ├── ListTile (leading: Icon(dark_mode), title: "Dark Mode",
    │          trailing: Switch(value: isDarkMode))
    ├── ListTile (leading: Icon(notifications), title: "Notifications",
    │          trailing: chevron, onTap: NotificationSettings)
    ├── Divider
    ├── SectionHeader ("Account")
    ├── ListTile (leading: Icon(payment), title: "Payment Methods",
    │          trailing: chevron, onTap: PaymentMethods)
    ├── ListTile (leading: Icon(history), title: "Ride History",
    │          trailing: chevron, onTap: RideHistory)
    ├── ListTile (leading: Icon(help), title: "Help & Support",
    │          trailing: chevron, onTap: HelpSupport)
    ├── ListTile (leading: Icon(info), title: "About ZIVVO",
    │          trailing: chevron, onTap: About)
    ├── Divider
    └── ListTile (leading: Icon(logout, color: Error), title: "Sign Out",
               titleColor: Error, onTap: confirm → sign out)

Customer Role Screens

Customer Home (Map + Where To)

Scaffold (extendBody: true, no AppBar)
└── Stack
    ├── FlutterMap (width: Expand, height: Expand)
    │   ├── TileLayer (urlTemplate: vector tile URL)
    │   ├── MarkerLayer — user location
    │   │   └── Marker (point: userLatLng)
    │   │       └── Container (w: 20, h: 20, radius: 10, color: Secondary,
    │   │              border: 3px white, shadow: teal glow)
    │   └── MarkerLayer — nearby drivers
    │       └── [Dynamic markers from driver positions]
    │           └── Image (src: car_icon, width: 32, height: 32, rotation: heading)
    ├── Positioned (top: safeAreaTop + 8, left: 16, right: 16)
    │   └── Row (mainAxisAlignment: SpaceBetween)
    │       ├── Container (w: 44, h: 44, radius: 22, color: white, shadow: sm)
    │       │   └── IconButton (icon: menu, onTap: open drawer)
    │       └── Container (w: 44, h: 44, radius: 22, color: white, shadow: sm)
    │           └── Stack
    │               ├── IconButton (icon: notifications_outlined, onTap: Notifications)
    │               └── Positioned (top: 0, right: 0)
    │                   └── Badge (count: unreadCount, color: Error)
    ├── DraggableScrollableSheet (initialChildSize: 0.25, minChildSize: 0.15,
    │      maxChildSize: 0.85)
    │   └── Container (radius: topLeft 20, topRight 20, color: Surface, shadow: xl)
    │       └── Column
    │           ├── Center
    │           │   └── Container (w: 40, h: 4, radius: 2, color: Divider, margin: top 8)
    │           ├── SizedBox (height: 16)
    │           ├── Container (margin: horizontal 16, padding: 0)
    │           │   └── Row
    │           │       ├── Container (w: 3, h: 48, radius: 1.5, color: Primary)
    │           │       └── Expanded
    │           │           └── ZivvoInput (hintText: "Where to?",
    │           │                  prefixIcon: search, readOnly: true,
    │           │                  onTap: navigate to DestinationSearch)
    │           ├── SizedBox (height: 16)
    │           ├── Container (height: 40, padding: horizontal 16)
    │           │   └── ListView (direction: Horizontal, spacing: 8)
    │           │       ├── ZivvoChip (icon: home, text: "Home", onTap: set destination)
    │           │       ├── ZivvoChip (icon: work, text: "Work", onTap: set destination)
    │           │       └── ZivvoChip (icon: bookmark, text: "Saved", onTap: SavedPlaces)
    │           └── SizedBox (height: 16)

Destination Search Screen

Scaffold (AppBar: none)
└── Column
    ├── Container (padding: 16, color: Surface)
    │   └── Column (spacing: 12)
    │       ├── Row
    │       │   ├── IconButton (icon: arrow_back, onTap: pop)
    │       │   └── Expanded
    │       │       └── Text ("Plan your trip", style: headingMedium)
    │       ├── Row (spacing: 12)
    │       │   ├── Column (width: 24, spacing: 4)
    │       │   │   ├── Container (w: 10, h: 10, radius: 5, color: Primary)
    │       │   │   ├── Container (w: 2, h: 24, color: Divider)
    │       │   │   └── Container (w: 10, h: 10, radius: 2, color: Error)
    │       │   └── Expanded
    │       │       └── Column (spacing: 8)
    │       │           ├── ZivvoInput (hintText: "Pickup location", value: currentAddress)
    │       │           └── ZivvoInput (hintText: "Where to?", autofocus: true)
    ├── Expanded
    │   └── ListView
    │       ├── SectionHeader ("Recent")
    │       ├── [RecentPlaceRow] × N
    │       │   └── ListTile (leading: Icon(history), title: place name,
    │       │          subtitle: address, onTap: select destination)
    │       ├── SectionHeader ("Saved Places")
    │       └── [SavedPlaceRow] × N
    │           └── ListTile (leading: Icon(star), title: place name,
    │                  subtitle: address, onTap: select destination)

Vehicle Selection & Fare Estimate

Scaffold (AppBar: back button, "Choose a ride")
└── Column
    ├── Container (height: 200)
    │   └── FlutterMap (showing route polyline, pickup/dropoff markers)
    ├── Expanded
    │   └── ListView (padding: 16, spacing: 8)
    │       ├── VehicleOption (selected state)
    │       │   └── ZivvoCard (border: 2px Primary when selected)
    │       │       └── Row (spacing: 12)
    │       │           ├── Image (src: economy_car, width: 64, height: 40, fit: Contain)
    │       │           ├── Expanded
    │       │           │   └── Column (crossAxisAlignment: Start)
    │       │           │       ├── Row
    │       │           │       │   ├── Text ("Economy", style: titleLarge)
    │       │           │       │   └── Badge ("Popular", color: Primary Wash)
    │       │           │       └── Text ("4 min away • 4 seats", style: bodySmall, color: TextSecondary)
    │       │           └── Column (crossAxisAlignment: End)
    │       │               ├── Text ("2,500 XAF", style: titleLarge, weight: 700)
    │       │               └── Text ("~15 min", style: bodySmall, color: TextSecondary)
    │       ├── VehicleOption (Comfort)
    │       │   └── ... (same structure, different image/price/time)
    │       ├── VehicleOption (Premium)
    │       │   └── ... (same structure)
    │       └── VehicleOption (Moto)
    │           └── ... (same structure, motorcycle image, 1 seat)
    ├── Container (padding: 16, color: Surface, shadow: xl)
    │   └── Column (spacing: 12)
    │       ├── Row (mainAxisAlignment: SpaceBetween)
    │       │   ├── Row (spacing: 8)
    │       │   │   ├── Icon (payment, color: Primary)
    │       │   │   └── Text ("MTN MoMo", style: bodyMedium)
    │       │   └── TextButton ("Change", color: Secondary)
    │       └── ZivvoButtonPrimary (text: "Book Economy • 2,500 XAF",
    │              width: Expand, onTap: request ride)

Active Ride Tracking

Scaffold (extendBody: true, no AppBar)
└── Stack
    ├── FlutterMap (width: Expand, height: Expand)
    │   ├── TileLayer
    │   ├── PolylineLayer
    │   │   └── Polyline (points: routeCoords, color: Secondary, strokeWidth: 5)
    │   ├── MarkerLayer
    │   │   ├── Marker (pickup: gold pin icon)
    │   │   └── Marker (dropoff: red pin icon)
    │   └── MarkerLayer (animated)
    │       └── Marker (driver: car icon, rotated to heading, animated position)
    ├── Positioned (top: safeAreaTop + 8, left: 16, right: 16)
    │   └── ZivvoCard
    │       └── Row (mainAxisAlignment: SpaceBetween)
    │           ├── Column (crossAxisAlignment: Start)
    │           │   ├── Text ("Arriving in", style: bodySmall, color: TextSecondary)
    │           │   └── Text ("4 min", style: headingLarge, color: Secondary)
    │           └── Column (crossAxisAlignment: End)
    │               ├── Text ("Distance", style: bodySmall, color: TextSecondary)
    │               └── Text ("1.2 km", style: headingMedium)
    ├── DraggableScrollableSheet (initialChildSize: 0.3, minChildSize: 0.15)
    │   └── Container (radius: top 20, color: Surface, shadow: xl)
    │       └── Column
    │           ├── Handle bar (same as home screen)
    │           ├── Container (padding: 16)
    │           │   └── Row (spacing: 12)
    │           │       ├── ZivvoAvatar (src: driverPhoto, size: 48)
    │           │       ├── Expanded
    │           │       │   └── Column (crossAxisAlignment: Start)
    │           │       │       ├── Text (driverName, style: titleLarge)
    │           │       │       └── Row (spacing: 4)
    │           │       │           ├── Icon (star, color: Primary, size: 16)
    │           │       │           └── Text ("4.8", style: bodySmall)
    │           │       └── Column
    │           │           ├── Text (vehicleMake, style: bodySmall, color: TextSecondary)
    │           │           └── Text (licensePlate, style: labelLarge)
    │           ├── Divider
    │           ├── Container (padding: horizontal 16, vertical 8)
    │           │   └── Row (mainAxisAlignment: SpaceEvenly)
    │           │       ├── IconButton (icon: phone, label: "Call", onTap: call driver)
    │           │       ├── IconButton (icon: message, label: "Chat", onTap: open chat)
    │           │       └── IconButton (icon: share, label: "Share", onTap: share tracking link)
    │           ├── Divider
    │           ├── Container (padding: 16)
    │           │   └── Text ("Driver is on the way to pick you up",
    │           │          style: bodyMedium, color: TextSecondary, textAlign: Center)
    │           └── Container (padding: 16)
    │               └── ZivvoButtonDanger (text: "SOS Emergency",
    │                      width: Expand, icon: warning,
    │                      onTap: hold 3s → trigger SOS)

Ride Complete & Rating

Scaffold (AppBar: none)
└── Column (padding: 24)
    ├── SizedBox (height: 48)
    ├── Icon (check_circle, color: Success, size: 64)
    ├── SizedBox (height: 16)
    ├── Text ("Trip Complete!", style: headlineLarge, textAlign: Center)
    ├── SizedBox (height: 32)
    ├── ZivvoCard
    │   └── Column (spacing: 12)
    │       ├── Row (mainAxisAlignment: SpaceBetween)
    │       │   ├── Text ("Total Fare", style: bodyMedium, color: TextSecondary)
    │       │   └── Text ("2,500 XAF", style: headingMedium, weight: 700)
    │       ├── Divider
    │       ├── Row (mainAxisAlignment: SpaceBetween)
    │       │   ├── Text ("Distance", style: bodySmall, color: TextSecondary)
    │       │   └── Text ("4.2 km", style: bodyMedium)
    │       ├── Row (mainAxisAlignment: SpaceBetween)
    │       │   ├── Text ("Duration", style: bodySmall, color: TextSecondary)
    │       │   └── Text ("15 min", style: bodyMedium)
    │       └── Row (mainAxisAlignment: SpaceBetween)
    │           ├── Text ("Payment", style: bodySmall, color: TextSecondary)
    │           └── Text ("MTN MoMo", style: bodyMedium)
    ├── SizedBox (height: 32)
    ├── Text ("Rate your driver", style: headingMedium, textAlign: Center)
    ├── SizedBox (height: 16)
    ├── Row (mainAxisAlignment: Center, spacing: 8)
    │   ├── ZivvoAvatar (src: driverPhoto, size: 56)
    │   └── Text (driverName, style: titleLarge)
    ├── SizedBox (height: 12)
    ├── RatingBar (initialRating: 5, itemCount: 5, itemSize: 40,
    │          activeColor: Primary, inactiveColor: Divider)
    ├── SizedBox (height: 16)
    ├── ZivvoInput (hintText: "Add a comment (optional)", maxLines: 3)
    ├── Spacer
    └── ZivvoButtonPrimary (text: "Done", width: Expand, onTap: submit → navigate home)

Driver Role Screens

Driver Home

Scaffold (extendBody: true, no AppBar)
└── Stack
    ├── FlutterMap (width: Expand, height: Expand)
    │   └── TileLayer + optional demand heatmap overlay
    ├── Positioned (top: safeAreaTop + 8, left: 16, right: 16)
    │   └── ZivvoCard
    │       └── Row (mainAxisAlignment: SpaceBetween)
    │           ├── Row (spacing: 12)
    │           │   ├── ZivvoAvatar (src: driverSelfie, size: 40)
    │           │   └── Column (crossAxisAlignment: Start)
    │           │       ├── Text (driverName, style: titleLarge)
    │           │       └── Row (spacing: 4)
    │           │           ├── Icon (star, color: Primary, size: 14)
    │           │           ├── Text ("4.8", style: bodySmall)
    │           │           └── Badge ("Gold", color: Primary Wash, textColor: Primary)
    │           └── Switch (value: isOnline, activeColor: Primary,
    │                  onChanged: toggle availability)
    ├── Positioned (bottom: 16, left: 16, right: 16)
    │   └── ZivvoCard
    │       └── Column (spacing: 8)
    │           ├── Row (mainAxisAlignment: SpaceEvenly)
    │           │   ├── Column (crossAxisAlignment: Center)
    │           │   │   ├── Text ("12,500 XAF", style: headingMedium, color: Primary)
    │           │   │   └── Text ("Today's earnings", style: bodySmall, color: TextSecondary)
    │           │   ├── Container (w: 1, h: 40, color: Divider)
    │           │   └── Column (crossAxisAlignment: Center)
    │           │       ├── Text ("7", style: headingMedium)
    │           │       └── Text ("Trips", style: bodySmall, color: TextSecondary)
    │           └── Text (isOnline ? "You're online" : "You're offline",
    │                  style: bodyMedium, color: isOnline ? Secondary : TextSecondary,
    │                  textAlign: Center)

Ride Request Card (Incoming)

AnimatedContainer (slide up from bottom, duration: 500ms)
└── ZivvoCardElevated (margin: 16)
    └── Column (spacing: 12)
        ├── Row (spacing: 12)
        │   ├── ZivvoAvatar (src: customerPhoto, size: 48)
        │   ├── Expanded
        │   │   └── Column (crossAxisAlignment: Start)
        │   │       ├── Text (customerName, style: titleLarge)
        │   │       └── Row (spacing: 4)
        │   │           ├── Icon (star, color: Primary, size: 14)
        │   │           └── Text ("4.6 • 23 rides", style: bodySmall, color: TextSecondary)
        │   └── Text ("2,500 XAF", style: headingMedium, weight: 700, color: Primary)
        ├── Divider
        ├── Row (spacing: 8)
        │   ├── Icon (circle, color: Primary, size: 12)
        │   ├── Expanded
        │   │   └── Text (pickupAddress, style: bodyMedium, maxLines: 1, overflow: Ellipsis)
        │   └── Text ("1.2 km", style: bodySmall, color: TextSecondary)
        ├── Row (spacing: 8)
        │   ├── Icon (location_on, color: Error, size: 12)
        │   └── Expanded
        │       └── Text (dropoffAddress, style: bodyMedium, maxLines: 1, overflow: Ellipsis)
        ├── SizedBox (height: 4)
        ├── Center
        │   └── Stack
        │       ├── CircularProgressIndicator (value: countdown/30, color: Secondary,
        │       │      strokeWidth: 4, size: 56)
        │       └── Text (countdownSeconds, style: headingMedium)
        ├── SizedBox (height: 4)
        └── Row (spacing: 12)
            ├── Expanded
            │   └── ZivvoButtonGhost (text: "Decline", onTap: decline request)
            └── Expanded
                └── ZivvoButtonPrimary (text: "Accept", onTap: accept request)

Driver Navigation (Active Trip)

Scaffold (extendBody: true, no AppBar)
└── Stack
    ├── FlutterMap (full screen)
    │   ├── PolylineLayer (route to pickup/dropoff, color: Secondary, width: 5)
    │   ├── MarkerLayer (pickup pin, dropoff pin)
    │   └── MarkerLayer (driver position, animated)
    ├── Positioned (top: safeAreaTop, left: 0, right: 0)
    │   └── Container (color: Secondary, padding: 16)
    │       └── Column
    │           ├── Text ("Head to pickup", style: bodyMedium, color: white)
    │           ├── Text ("Turn right on Rue de la Joie", style: headingMedium, color: white)
    │           └── Row (spacing: 16)
    │               ├── Text ("1.2 km", style: headingLarge, color: white)
    │               └── Text ("4 min", style: headingLarge, color: white)
    ├── Positioned (bottom: 0, left: 0, right: 0)
    │   └── ZivvoCard (radiusTopOnly: 20)
    │       └── Column (padding: 16, spacing: 12)
    │           ├── Row (spacing: 12)
    │           │   ├── ZivvoAvatar (src: customerPhoto, size: 40)
    │           │   ├── Expanded → Column
    │           │   │   ├── Text (customerName, style: titleLarge)
    │           │   │   └── Text (pickupAddress, style: bodySmall, color: TextSecondary)
    │           │   ├── IconButton (icon: phone, onTap: call customer)
    │           │   └── IconButton (icon: message, onTap: open chat)
    │           └── ZivvoButtonPrimary (text: "Arrived at Pickup",
    │                  width: Expand, onTap: update trip status)

Dealer Role Screens

Dealer Dashboard

Scaffold (AppBar: title "Dashboard", actions: [notifications, settings])
└── ListView (padding: 16, spacing: 16)
    ├── ZivvoCard (gradient: Sunrise 5%)
    │   └── Column (spacing: 8)
    │       ├── Text ("Welcome back, Jean", style: headingMedium)
    │       ├── Text ("Here's your fleet overview", style: bodyMedium, color: TextSecondary)
    │       └── Row (mainAxisAlignment: SpaceEvenly, spacing: 12)
    │           ├── StatColumn (value: "24", label: "Vehicles", icon: directions_car)
    │           ├── StatColumn (value: "18", label: "Active", icon: check_circle, color: Success)
    │           ├── StatColumn (value: "3", label: "Rented", icon: key, color: Secondary)
    │           └── StatColumn (value: "3", label: "Idle", icon: pause_circle, color: Warning)
    ├── ZivvoCard
    │   └── Column (spacing: 12)
    │       ├── Row (mainAxisAlignment: SpaceBetween)
    │       │   ├── Text ("Revenue", style: titleLarge)
    │       │   └── DropDown (options: ["This Week", "This Month", "This Year"])
    │       ├── Text ("485,000 XAF", style: displayMedium, color: Primary)
    │       ├── Row (spacing: 4)
    │       │   ├── Icon (trending_up, color: Success, size: 16)
    │       │   └── Text ("+12% vs last week", style: bodySmall, color: Success)
    │       └── Chart (type: Line, height: 150, color: Primary)
    ├── Row (mainAxisAlignment: SpaceBetween)
    │   ├── Text ("Pending Requests", style: titleLarge)
    │   └── TextButton ("View All", color: Secondary)
    ├── [RentalRequestCard] × 2-3
    │   └── ZivvoCard
    │       └── Row (spacing: 12)
    │           ├── CircleImage (customer photo)
    │           ├── Expanded → Column
    │           │   ├── Text (customerName, style: titleLarge)
    │           │   └── Text ("Toyota Corolla • 3 days", style: bodySmall)
    │           └── Column
    │               ├── ZivvoButtonPrimary (text: "Accept", height: 36)
    │               └── ZivvoButtonGhost (text: "Decline", height: 36)
    └── SizedBox (height: 80) // bottom nav clearance

Vehicle Management (Fleet List)

Scaffold (AppBar: title "My Fleet", actions: [filter, sort])
├── FloatingActionButton (icon: add, onTap: AddVehicle)
└── ListView (padding: 16, spacing: 12)
    └── [VehicleCard] × N
        └── ZivvoCard
            └── Row (spacing: 12)
                ├── Container (width: 100, height: 80, radius: 12)
                │   └── Image (src: vehiclePhoto, fit: Cover)
                ├── Expanded
                │   └── Column (crossAxisAlignment: Start, spacing: 4)
                │       ├── Text ("Toyota Corolla 2021", style: titleLarge)
                │       ├── Text ("LT 1234 AB", style: bodySmall, color: TextSecondary)
                │       ├── Row (spacing: 4)
                │       │   └── Badge (status: "Active", color: conditional)
                │       └── Text ("15,000 XAF/day", style: labelLarge, color: Primary)
                └── IconButton (icon: more_vert, onTap: vehicle options menu)

Admin Role Screens

Admin Dashboard

Scaffold (AppBar: title "Admin", actions: [notifications])
└── ListView (padding: 16, spacing: 16)
    ├── Row (spacing: 12)
    │   ├── Expanded → ZivvoCard
    │   │   └── Column
    │   │       ├── Icon (people, color: Secondary, size: 32)
    │   │       ├── Text ("12,450", style: headingLarge)
    │   │       └── Text ("Total Users", style: bodySmall, color: TextSecondary)
    │   └── Expanded → ZivvoCard
    │       └── Column
    │           ├── Icon (directions_car, color: Primary, size: 32)
    │           ├── Text ("342", style: headingLarge)
    │           └── Text ("Active Rides", style: bodySmall, color: TextSecondary)
    ├── Row (spacing: 12)
    │   ├── Expanded → ZivvoCard
    │   │   └── Column
    │   │       ├── Icon (verified, color: Success, size: 32)
    │   │       ├── Text ("89", style: headingLarge)
    │   │       └── Text ("KYC Pending", style: bodySmall, color: Warning)
    │   └── Expanded → ZivvoCard
    │       └── Column
    │           ├── Icon (warning, color: Error, size: 32)
    │           ├── Text ("3", style: headingLarge)
    │           └── Text ("Active SOS", style: bodySmall, color: Error)
    ├── ZivvoCard
    │   └── Column (spacing: 12)
    │       ├── Text ("Revenue Today", style: titleLarge)
    │       ├── Text ("1,250,000 XAF", style: displayMedium, color: Primary)
    │       └── Chart (type: Bar, height: 150)
    └── ZivvoCard
        └── Column (spacing: 8)
            ├── Text ("Recent Activity", style: titleLarge)
            └── [ActivityRow] × 5
                └── ListTile (leading: avatar, title: action, subtitle: timestamp)

KYC Review Screen

Scaffold (AppBar: title "KYC Review", back button)
└── ListView (padding: 16, spacing: 16)
    ├── ZivvoCard
    │   └── Column (spacing: 12)
    │       ├── Row (spacing: 12)
    │       │   ├── ZivvoAvatar (src: applicantPhoto, size: 64)
    │       │   └── Column (crossAxisAlignment: Start)
    │       │       ├── Text (applicantName, style: headingMedium)
    │       │       ├── Text ("Driver Application", style: bodyMedium, color: TextSecondary)
    │       │       └── Text ("Submitted 2h ago", style: bodySmall, color: TextSecondary)
    │       ├── Divider
    │       ├── Text ("Identity Document", style: titleLarge)
    │       ├── Image (src: idFrontPhoto, width: Expand, height: 200, fit: Contain, radius: 12)
    │       ├── Image (src: idBackPhoto, width: Expand, height: 200, fit: Contain, radius: 12)
    │       ├── Divider
    │       ├── Text ("Driver's License", style: titleLarge)
    │       ├── Image (src: licensePhoto, width: Expand, height: 200, fit: Contain, radius: 12)
    │       ├── Divider
    │       ├── Text ("Vehicle Registration", style: titleLarge)
    │       ├── Image (src: registrationPhoto, width: Expand, height: 200, fit: Contain, radius: 12)
    │       ├── Divider
    │       ├── Text ("Selfie Verification", style: titleLarge)
    │       ├── Row (spacing: 12)
    │       │   ├── Image (src: selfiePhoto, width: 150, height: 150, fit: Cover, radius: 12)
    │       │   └── Column
    │       │       ├── Row → Icon(check) + Text("Face match: 94%")
    │       │       └── Row → Icon(check) + Text("Liveness: Passed")
    ├── ZivvoInput (hintText: "Rejection reason (if applicable)", maxLines: 3)
    ├── Row (spacing: 12)
    │   ├── Expanded
    │   │   └── ZivvoButtonDanger (text: "Reject", onTap: reject with reason)
    │   └── Expanded
    │       └── ZivvoButtonPrimary (text: "Approve", onTap: approve KYC)

Bottom Navigation Bars

Customer Bottom Nav

BottomNavigationBar (type: Fixed, backgroundColor: Surface, elevation: 8)
├── Item (icon: home, label: "Home", activeColor: Primary)
├── Item (icon: history, label: "Rides", activeColor: Primary)
├── Item (icon: directions_car, label: "Rentals", activeColor: Primary)
└── Item (icon: person, label: "Account", activeColor: Primary)

Driver Bottom Nav

BottomNavigationBar
├── Item (icon: map, label: "Home")
├── Item (icon: list, label: "Trips")
├── Item (icon: account_balance_wallet, label: "Earnings")
└── Item (icon: person, label: "Account")

Dealer Bottom Nav

BottomNavigationBar
├── Item (icon: dashboard, label: "Dashboard")
├── Item (icon: directions_car, label: "Fleet")
├── Item (icon: assignment, label: "Requests")
└── Item (icon: person, label: "Account")

Admin Bottom Nav

BottomNavigationBar
├── Item (icon: dashboard, label: "Dashboard")
├── Item (icon: people, label: "Users")
├── Item (icon: verified_user, label: "KYC")
├── Item (icon: report, label: "Disputes")
└── Item (icon: settings, label: "Settings")