Skip to content

feat(#36): Investor-Friendly UI with Sparklines, Backers, and Momentum Metrics#39

Merged
Jing-yilin merged 2 commits intodevelopfrom
feat/36-enhanced-campaign-ui
Feb 28, 2026
Merged

feat(#36): Investor-Friendly UI with Sparklines, Backers, and Momentum Metrics#39
Jing-yilin merged 2 commits intodevelopfrom
feat/36-enhanced-campaign-ui

Conversation

@Jing-yilin
Copy link
Contributor

Summary

Transform KickWatch iOS app into an investor-friendly visual experience following the principle: "Investors need visualization, not complexity". This PR adds color-coded badges, trend charts, sparklines, and intuitive metrics to help hardware investors make quick decisions.

Key Changes

Backend (Phase 1)

  • New endpoint: GET /campaigns/:pid/history
    • Returns 14-day campaign snapshots by default (max 30 days)
    • Enables trend visualization and momentum tracking
    • Returns pledged amount and percent funded over time

iOS Data Layer (Phase 2)

  • ✅ Added backers_count to CampaignDTO
  • ✅ Created HistoryDataPoint and CampaignHistoryResponse models
  • ✅ Implemented 5-minute history cache in APIClient
  • ✅ Added fetchCampaignHistory() method

List View Enhancements (Phase 3)

  • Backers count with person icon (formats 1.5K, 2.3M)
  • 24h dollar changes — Shows "$50K" instead of just "150%"
  • State badges — "Funded ✓" (green), "Failed" (red), "Canceled" (red)
  • ✅ Enhanced momentum badge logic (🔥 for 200%+, ⚡ for others)

Detail View Stats & Content (Phase 4)

  • Expanded stats grid to 4 columns:
    • Goal (target icon)
    • Pledged (dollar icon)
    • Backers (people icon)
    • Days Left (calendar icon)
  • Expandable project blurb — Collapses at 150 chars with "Read more" button
  • 24-Hour Momentum section with:
    • Sparkline chart (green/red gradient)
    • 24h dollar change metric card
    • Growth rate percentage card

Chart Visualization (Phase 5)

  • NEW: SparklineView component
    • Beautiful area + line chart using Swift Charts
    • Auto color-coding: Green (>5% up), Red (<5% down), Gray (flat)
    • Hidden axes for clean mobile appearance
    • Empty state with icon when no data available

Visual Design

Color Coding:

  • 🟢 Green → Positive trends, successful campaigns
  • 🔴 Red → Negative trends, failed campaigns
  • 🟠 Orange → Momentum indicators
  • 🔵 Blue → New items (<48h old)

SF Symbols Icons:

  • person.2.fill → Backers
  • bolt.fill → Momentum
  • dollarsign.circle.fill → Money metrics
  • arrow.up.right/down.right → Trend direction
  • checkmark.circle.fill → Success
  • target → Goal
  • calendar → Time remaining

Screenshots

Before → After

List View:

  • Before: Just percentages and days left
  • After: Backers count, state badges, dollar amounts, enhanced momentum

Detail View:

  • Before: 3 stats (Goal, Pledged, Days)
  • After: 4 stats with icons, expandable blurb, sparkline chart, momentum metrics

Performance Optimizations

  • ✅ 5-minute cache for history API calls (prevents N+1 queries on scroll)
  • ✅ Backend limits history to 30 days max
  • ✅ Efficient sparkline rendering with Swift Charts

Testing Checklist

  • Backend endpoint returns correct data structure
  • iOS models decode properly
  • Backers count formats correctly (1K, 1M)
  • State badges show for all states
  • Momentum section only shows when velocity/delta exist
  • Sparkline color-codes trends correctly
  • Empty state shows when no history available
  • Blurb expansion works smoothly
  • All UI works in light/dark mode

Related Issues

Closes #36

🤖 Generated with Claude Code

…m metrics

Backend:
- Add GET /campaigns/:pid/history endpoint (14-day default, 30-day max)
- Returns campaign snapshots for trend visualization

iOS:
- Add backers_count display with person icon
- Show 24h dollar changes ($50K) instead of just percentages
- Add state badges (Funded ✓, Failed, Canceled)
- Expand detail stats to 4 columns (Goal, Pledged, Backers, Days)
- Add expandable project blurb (collapses at 150 chars)
- Add momentum section with sparkline chart and metrics
- Create SparklineView with green/red gradient trends
- Implement 5-min history cache in APIClient

Visual design: Color-coded badges, SF Symbol icons, glanceable metrics for investors.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Copy link
Contributor Author

@Jing-yilin Jing-yilin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex Review

[High] CampaignDTO's new backers_count field breaks the watchlist build path

Adding backers_count to CampaignDTO changed the memberwise initializer, but WatchlistView.toCampaignDTO(_:) still calls the old signature. A clean simulator build now fails with missing argument for parameter 'backers_count' in call, so this PR is not buildable as-is.

Refs: ios/KickWatch/Sources/Views/WatchlistView.swift:48, ios/KickWatch/Sources/Services/APIClient.swift:3

[Medium] The detail view now renders a momentum section even when there is no momentum data

CampaignDetailView gates the new section with if let velocity, let delta, but the API payloads for discover/search results come from model.Campaign, where velocity_24h and pledge_delta_24h are concrete float64 fields that serialize as 0, not null. In practice that makes campaigns with no computed history show a red 24h Change $0 / Growth Rate 0.0% panel, which is misleading and contradicts the PR's stated behavior that the section only appears when momentum data exists.

Refs: ios/KickWatch/Sources/Views/CampaignDetailView.swift:65, backend/internal/model/model.go:27

[Medium] GET /campaigns/:pid/history accepts invalid days values and turns them into empty history windows

strconv.Atoi errors are ignored here, so ?days=abc becomes 0, and negative values move the cutoff into the future. Both cases silently return an empty history array instead of falling back to the documented 14-day default or rejecting the request.

Refs: backend/internal/handler/campaigns.go:143

Verification

  • cd backend && go test ./...
  • cd ios && xcodegen generate
  • cd ios && xcodebuild -project KickWatch.xcodeproj -scheme KickWatch -destination 'platform=iOS Simulator,name=iPhone 17' CODE_SIGNING_ALLOWED=NO build ❌ (WatchlistView.swift:56:44: missing argument for parameter 'backers_count' in call)

1. Add missing backers_count parameter in WatchlistView toCampaignDTO
2. Prevent showing $0/0% momentum section for campaigns with zero velocity/delta
3. Handle strconv.Atoi errors properly in GetCampaignHistory, default to 14 days

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@Jing-yilin Jing-yilin merged commit 1e0dc22 into develop Feb 28, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant