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

@@ -243,10 +243,12 @@ class SubmissionModel {
class DashboardResponse {
final UserGamificationProfile profile;
final List<SubmissionModel> submissions;
final List<AchievementBadge> achievements;
const DashboardResponse({
required this.profile,
this.submissions = const [],
this.achievements = const [],
});
}
@@ -330,4 +332,15 @@ class AchievementBadge {
required this.isUnlocked,
required this.progress,
});
factory AchievementBadge.fromJson(Map<String, dynamic> json) {
return AchievementBadge(
id: (json['id'] ?? json['badge_id'] ?? '').toString(),
title: (json['title'] ?? json['name'] ?? '').toString(),
description: (json['description'] ?? '').toString(),
iconName: (json['icon_name'] ?? json['icon'] ?? 'star').toString(),
isUnlocked: json['is_unlocked'] == true || json['unlocked'] == true,
progress: (json['progress'] as num?)?.toDouble() ?? 0.0,
);
}
}