fix: leaderboard empty on first open — decouple from loadAll()
LeaderboardScreen called loadAll() which uses Future.wait across 4 APIs. If getDashboard() fails (empty user_id before auth), the entire batch throws and leaderboard stays []. Switching districts worked because setDistrict() calls getLeaderboard() directly. - Add loadLeaderboard() to GamificationProvider — calls only getLeaderboard(), independent of dashboard/shop/achievements - Add isLeaderboardLoading field with correct lifecycle in setDistrict/setTimePeriod - LeaderboardScreen.initState now calls loadLeaderboard() instead of loadAll() Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,7 @@ class GamificationProvider extends ChangeNotifier {
|
||||
String leaderboardTimePeriod = 'all_time'; // 'all_time' | 'this_month'
|
||||
|
||||
bool isLoading = false;
|
||||
bool isLeaderboardLoading = false;
|
||||
String? error;
|
||||
|
||||
// TTL guard — prevents redundant API calls from multiple screens
|
||||
@@ -80,12 +81,36 @@ class GamificationProvider extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Load only leaderboard data — safe to call independently of loadAll().
|
||||
// Used by LeaderboardScreen so a dashboard/shop failure doesn't blank the list.
|
||||
// ---------------------------------------------------------------------------
|
||||
Future<void> loadLeaderboard() async {
|
||||
if (isLeaderboardLoading) return;
|
||||
isLeaderboardLoading = true;
|
||||
notifyListeners();
|
||||
try {
|
||||
final response = await _service.getLeaderboard(
|
||||
district: leaderboardDistrict,
|
||||
timePeriod: leaderboardTimePeriod,
|
||||
);
|
||||
leaderboard = response.entries;
|
||||
currentUserStats = response.currentUser;
|
||||
totalParticipants = response.totalParticipants;
|
||||
} catch (e) {
|
||||
error = userFriendlyError(e);
|
||||
}
|
||||
isLeaderboardLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Change district filter
|
||||
// ---------------------------------------------------------------------------
|
||||
Future<void> setDistrict(String district) async {
|
||||
if (leaderboardDistrict == district) return;
|
||||
leaderboardDistrict = district;
|
||||
isLeaderboardLoading = true;
|
||||
notifyListeners();
|
||||
try {
|
||||
final response = await _service.getLeaderboard(district: district, timePeriod: leaderboardTimePeriod);
|
||||
@@ -95,6 +120,7 @@ class GamificationProvider extends ChangeNotifier {
|
||||
} catch (e) {
|
||||
error = userFriendlyError(e);
|
||||
}
|
||||
isLeaderboardLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@@ -104,6 +130,7 @@ class GamificationProvider extends ChangeNotifier {
|
||||
Future<void> setTimePeriod(String period) async {
|
||||
if (leaderboardTimePeriod == period) return;
|
||||
leaderboardTimePeriod = period;
|
||||
isLeaderboardLoading = true;
|
||||
notifyListeners();
|
||||
try {
|
||||
final response = await _service.getLeaderboard(district: leaderboardDistrict, timePeriod: period);
|
||||
@@ -113,6 +140,7 @@ class GamificationProvider extends ChangeNotifier {
|
||||
} catch (e) {
|
||||
error = userFriendlyError(e);
|
||||
}
|
||||
isLeaderboardLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user