// lib/features/gamification/providers/gamification_provider.dart import 'package:flutter/foundation.dart'; import '../../../core/utils/error_utils.dart'; import '../models/gamification_models.dart'; import '../services/gamification_service.dart'; class GamificationProvider extends ChangeNotifier { final GamificationService _service = GamificationService(); // State UserGamificationProfile? profile; List leaderboard = []; List shopItems = []; List achievements = []; // Leaderboard filters — matches web version String leaderboardDistrict = 'Overall Kerala'; String leaderboardTimePeriod = 'all_time'; // 'all_time' | 'this_month' bool isLoading = false; String? error; // --------------------------------------------------------------------------- // Load everything at once (called when ContributeScreen is mounted) // --------------------------------------------------------------------------- Future loadAll() async { isLoading = true; error = null; notifyListeners(); try { final results = await Future.wait([ _service.getProfile(), _service.getLeaderboard(district: leaderboardDistrict, timePeriod: leaderboardTimePeriod), _service.getShopItems(), _service.getAchievements(), ]); profile = results[0] as UserGamificationProfile; leaderboard = results[1] as List; shopItems = results[2] as List; achievements = results[3] as List; } catch (e) { error = userFriendlyError(e); } finally { isLoading = false; notifyListeners(); } } // --------------------------------------------------------------------------- // Change district filter // --------------------------------------------------------------------------- Future setDistrict(String district) async { if (leaderboardDistrict == district) return; leaderboardDistrict = district; notifyListeners(); try { leaderboard = await _service.getLeaderboard(district: district, timePeriod: leaderboardTimePeriod); } catch (e) { error = userFriendlyError(e); } notifyListeners(); } // --------------------------------------------------------------------------- // Change time period filter // --------------------------------------------------------------------------- Future setTimePeriod(String period) async { if (leaderboardTimePeriod == period) return; leaderboardTimePeriod = period; notifyListeners(); try { leaderboard = await _service.getLeaderboard(district: leaderboardDistrict, timePeriod: period); } catch (e) { error = userFriendlyError(e); } notifyListeners(); } // --------------------------------------------------------------------------- // Redeem a shop item — deducts RP locally optimistically, returns voucher code // --------------------------------------------------------------------------- Future redeemItem(String itemId) async { final item = shopItems.firstWhere((s) => s.id == itemId); // Optimistically deduct RP if (profile != null) { profile = UserGamificationProfile( userId: profile!.userId, lifetimeEp: profile!.lifetimeEp, currentEp: profile!.currentEp, currentRp: profile!.currentRp - item.rpCost, tier: profile!.tier, ); notifyListeners(); } try { final record = await _service.redeemItem(itemId); return record.voucherCode; } catch (e) { // Rollback on failure if (profile != null) { profile = UserGamificationProfile( userId: profile!.userId, lifetimeEp: profile!.lifetimeEp, currentEp: profile!.currentEp, currentRp: profile!.currentRp + item.rpCost, tier: profile!.tier, ); notifyListeners(); } rethrow; } } // --------------------------------------------------------------------------- // Submit a contribution // --------------------------------------------------------------------------- Future submitContribution(Map data) async { await _service.submitContribution(data); } }