feat: Phase 2 — 11 high-priority gaps implemented across home, auth, gamification, profile, and event detail

Phase 2 gaps completed:
- HOME-001: Hero slider pause-on-touch (GestureDetector wraps PageView)
- HOME-003: Calendar bottom sheet with TableCalendar (replaces custom dialog)
- AUTH-004: District dropdown on signup (14 Kerala districts)
- EVT-003: Mobile sticky "Book Now" bar + desktop CTA wired to CheckoutScreen
- ACH-001: Real achievements from dashboard API with fallback defaults
- GAM-002: 3-card EP row (Lifetime EP / Liquid EP / Reward Points)
- GAM-005: Horizontal tier roadmap Bronze→Silver→Gold→Platinum→Diamond
- CTR-001: Submission status chips (PENDING/APPROVED/REJECTED)
- CTR-002: +EP badge on approved submissions
- PROF-003: Gamification cards on profile screen with Consumer<GamificationProvider>
- UX-001: Shimmer skeleton loaders (shimmer ^3.0.0) replacing CircularProgressIndicator

Already complete (verified, no changes needed):
- HOME-002: Category shelves already built in _buildTypeSection()
- LDR-002: Podium visualization already built (_buildPodium / _buildDesktopPodium)
- BOOK-004: UPI handled natively by Razorpay SDK

Deferred: LOC-001/002 (needs Django haversine endpoint)
Skipped: AUTH-002 (OTP needs SMS provider decision)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-04 16:51:30 +05:30
parent 8955febd00
commit e365361451
12 changed files with 715 additions and 250 deletions

View File

@@ -28,14 +28,20 @@ class GamificationService {
final profileJson = res['profile'] as Map<String, dynamic>? ?? {};
final rawSubs = res['submissions'] as List? ?? [];
final rawAchievements = res['achievements'] as List? ?? [];
final submissions = rawSubs
.map((s) => SubmissionModel.fromJson(Map<String, dynamic>.from(s as Map)))
.toList();
final achievements = rawAchievements
.map((a) => AchievementBadge.fromJson(Map<String, dynamic>.from(a as Map)))
.toList();
return DashboardResponse(
profile: UserGamificationProfile.fromJson(profileJson),
submissions: submissions,
achievements: achievements,
);
}
@@ -132,42 +138,25 @@ class GamificationService {
}
// ---------------------------------------------------------------------------
// Achievements
// TODO: wire to achievements API when available on Node.js server
// Achievements — sourced from dashboard API `achievements` array.
// Falls back to default badges if API doesn't return achievements yet.
// ---------------------------------------------------------------------------
Future<List<AchievementBadge>> getAchievements() async {
await Future.delayed(const Duration(milliseconds: 300));
return const [
AchievementBadge(
id: 'badge-01', title: 'First Submission',
description: 'Submitted your first event.',
iconName: 'edit', isUnlocked: true, progress: 1.0,
),
AchievementBadge(
id: 'badge-02', title: 'Silver Streak',
description: 'Reached Silver tier.',
iconName: 'star', isUnlocked: true, progress: 1.0,
),
AchievementBadge(
id: 'badge-03', title: 'Gold Rush',
description: 'Reach Gold tier (500 EP).',
iconName: 'emoji_events', isUnlocked: false, progress: 0.64,
),
AchievementBadge(
id: 'badge-04', title: 'Top 10',
description: 'Appear in the district leaderboard top 10.',
iconName: 'leaderboard', isUnlocked: false, progress: 0.5,
),
AchievementBadge(
id: 'badge-05', title: 'Image Pro',
description: 'Submit 10 events with 3+ images.',
iconName: 'photo_library', isUnlocked: false, progress: 0.3,
),
AchievementBadge(
id: 'badge-06', title: 'Pioneer',
description: 'One of the first 100 contributors.',
iconName: 'verified', isUnlocked: true, progress: 1.0,
),
];
try {
final dashboard = await getDashboard();
if (dashboard.achievements.isNotEmpty) return dashboard.achievements;
} catch (_) {
// Fall through to defaults
}
return _defaultBadges;
}
static const _defaultBadges = [
AchievementBadge(id: 'badge-01', title: 'First Submission', description: 'Submitted your first event.', iconName: 'edit', isUnlocked: false, progress: 0.0),
AchievementBadge(id: 'badge-02', title: 'Silver Streak', description: 'Reached Silver tier.', iconName: 'star', isUnlocked: false, progress: 0.0),
AchievementBadge(id: 'badge-03', title: 'Gold Rush', description: 'Reach Gold tier (500 EP).', iconName: 'emoji_events', isUnlocked: false, progress: 0.0),
AchievementBadge(id: 'badge-04', title: 'Top 10', description: 'Appear in the district leaderboard top 10.', iconName: 'leaderboard', isUnlocked: false, progress: 0.0),
AchievementBadge(id: 'badge-05', title: 'Image Pro', description: 'Submit 10 events with 3+ images.', iconName: 'photo_library', isUnlocked: false, progress: 0.0),
AchievementBadge(id: 'badge-06', title: 'Pioneer', description: 'One of the first 100 contributors.', iconName: 'verified', isUnlocked: false, progress: 0.0),
];
}