Skip to content

Light Lantern Flows

This document maps out the two distinct user flows for lighting a lantern in the Lantern app. Both flows use shared logic via the useLightLantern hook and converge to the same success screen.

Architecture Overview

Shared Hook: useLightLantern

  • Handles Firebase lantern creation
  • Manages loading and error states
  • Triggers success/error callbacks

Shared Success Screen: ActiveLanternView

  • Displays lit lantern details
  • Shows mood, interest, time remaining
  • Allows extinguish action
  • Used by both Flow 1 and Flow 2

Flow 1: Light Lantern from Venue Detail

Entry point: User taps "Light My Lantern" button on a venue detail page

Screenshots: docs/screenshots/light_lantern_flows/flow_1_from_place/

Steps

  1. Venue Detail (step1_from_venue_light_lantern.png)

    • User views venue details
    • Taps "Light My Lantern" button
    • Code: VenueView component in Dashboard.jsx
    • Handler: handleLightLantern() → sets view='form'
  2. Enter Lantern Details (step2_enter_lantern_details.png)

    • User selects mood (Conversation, Quiet Company, Activity/Game)
    • User enters interest text (140 char max)
    • Taps "Light My Lantern" button
    • Code: LightLanternForm component in LightLanternForm.jsx
    • Handler: confirmLantern() → uses useLightLantern hook → sets view='active'
  3. Success & Lantern Details (step3_lit_lantern_success_and_details.png)

    • Shows lit lantern with celebration animation
    • Displays mood, interest, time remaining
    • Shows other active lanterns at venue
    • User can extinguish or wave to others
    • Code: ActiveLanternView component in Dashboard.jsx

Key Functions

  • handleLightLantern() - Entry point, sets view to form
  • confirmLantern(data) - Uses useLightLantern hook to light lantern, navigates to active view
  • useLightLantern() - Shared hook in useLightLantern.js

Flow 2: Light Lantern from Fire Icon (Global)

Entry point: User taps fire icon in Lantern Hub menu

Screenshots: docs/screenshots/light_lantern_flows/flow_2_from_fire_icon/

Steps

  1. Choose Light Lantern (step1_choose_light_lantern.png)

    • User opens Lantern Hub
    • Taps fire icon to light a lantern
    • Code: LanternHub component in Dashboard.jsx
    • Handler: handleLanternHubLightLantern() → sets showLightLanternModal=true
  2. Choose Venue (step2_choose_venue.png)

    • Modal shows nearby venues (map + list view)
    • User selects a venue
    • Code: VenuePicker component in VenuePicker.jsx
    • State: LightLanternModal manages flow, step='venue'
    • Handler: handleSelectVenue(venue) → sets selectedVenue, advances to step='form'
  3. Enter Lantern Details (step3_enter_lantern_details.png)

    • User selects mood (Conversation, Quiet Company, Activity/Game)
    • User enters interest text (140 char max)
    • Taps "Light My Lantern" button
    • Code: LightLanternForm component embedded in modal
    • Handler: handleFormConfirm(data) → uses useLightLantern hook → closes modal
  4. Success Screen (step4_lit_lantern_success_and_details.png)

    • Modal closes, returns to Dashboard
    • Dashboard shows ActiveLanternView with celebration animation
    • Displays mood, interest, status
    • Same view as Flow 1
    • Code: ActiveLanternView component in Dashboard.jsx
    • Flow: Modal's onLanternLit() callback → Dashboard sets view='active'

Key Functions

  • handleLanternHubLightLantern() - Entry point, opens modal
  • LightLanternModal component - Manages 2-step flow (venue → form), then closes
  • handleFormConfirm(data) - Uses useLightLantern hook to light lantern and close modal
  • Modal's onLanternLit() callback - Triggers Dashboard to show ActiveLanternView
  • useLightLantern() - Shared hook in useLightLantern.js
  • handleSuccessClose() - Closes modal and passes lantern data to Dashboard
  • onLanternLit(lanternData) - Dashboard callback, navigates to ActiveLanternView

Component Architecture

Component Architecture

Shared Components

  • useLightLantern (useLightLantern.js)

    • Custom hook that centralizes Firebase lighting logic
    • Used by both flows
    • Handles loading, error states, and success/error callbacks
  • LightLanternForm (LightLanternForm.jsx)

    • Reusable form for mood + interest input
    • Used in both flows
    • Props: venue, onCancel, onConfirm, loading
  • VenuePicker (VenuePicker.jsx)

    • Map/list view of nearby venues
    • Only used in Flow 2
    • Shows distance, category, active lantern count
  • ActiveLanternView (Dashboard.jsx)

    • Final "success" view showing lit lantern
    • Used by both flows as the success screen
    • Shows lantern details, time remaining, other lanterns at venue
    • Allows user to extinguish or wave

Flow-Specific Components

  • Flow 1: Uses view state in Dashboard to navigate (venue → form → active)
  • Flow 2: Uses LightLanternModal (LightLanternModal.jsx) with internal step state (venue → form, then closes and triggers Dashboard's active view)

State Management

Flow 1 State (Dashboard.jsx)

javascript
const [view, setView] = useState('home') // 'home' | 'venue' | 'form' | 'active'
const [selectedVenue, setSelectedVenue] = useState(null)

// Computed from real-time listener
const myLantern = activeLanterns.length > 0 ? {
  ...activeLanterns[0],
  timeRemaining: formatTimeRemaining(activeLanterns[0])
} : null

Flow 2 State (LightLanternModal.jsx)

javascript
const [selectedVenue, setSelectedVenue] = useState(null)
const [lighting, setLighting] = useState(false)
const [userLocation, setUserLocation] = useState(null)

// Derived state - only 2 steps now
const step = selectedVenue ? 'form' : 'venue'

Shared Hook: useLightLantern

javascript
import { useLightLantern } from '../../hooks/useLightLantern'

const { lightLanternFlow, loading, error } = useLightLantern()

// Usage
await lightLanternFlow({
  userId: currentUser.uid,
  venueId: venue.id,
  location: { lat, lng },
  formData: { mood, interest },
  onSuccess: (lantern) => { ... },
  onError: (error) => { ... }
})

The hook:

  • Calls lightLantern() from lanternService.js
  • Manages loading and error states
  • Invokes callbacks on success/error
  • Used identically by both flows

Refactor Summary (2026-01-07)

Changes Made

  1. Created useLightLantern hook (useLightLantern.js)

    • Centralizes Firebase lighting logic
    • Eliminates duplicate code between flows
    • Single source of truth for lantern creation
  2. Refactored Flow 1 (Dashboard.jsx)

    • confirmLantern() now uses useLightLantern hook
    • Removed duplicate Firebase call logic
  3. Refactored Flow 2 (LightLanternModal.jsx)

    • handleFormConfirm() now uses useLightLantern hook
    • Removed success step from modal - modal just closes
    • Dashboard's onLanternLit callback shows ActiveLanternView
    • Simplified from 3 steps (venue → form → success) to 2 steps (venue → form)
  4. Fixed bugs

    • Removed intermediate success screen from Flow 1
    • Fixed blank screen when viewing lantern details from fire icon
    • Both flows now properly navigate to ActiveLanternView

Benefits

Single source of truth - Both flows use same hook
Code reduction - ~60 lines of duplication eliminated
Converged UX - Both flows end at same success screen
Easier to maintain - Change lighting logic once, affects both flows
Simpler modal - No success screen state management in modal
Bugs fixed - Blank screen and duplicate success screens resolved


Testing

To test flows:

  1. Flow 1:

    • Navigate to venue detail from map
    • Tap "Light My Lantern"
    • Fill form and submit
    • Should see ActiveLanternView immediately
  2. Flow 2:

    • Tap fire icon in Lantern Hub
    • Select venue from picker
    • Fill form and submit
    • Should see success screen in modal
    • Tap "Got it!" to close and see ActiveLanternView

See VENUE_TESTING_GUIDE.md for venue testing setup.

Built with VitePress