Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/dreancaste/TriviaPP/llms.txt

Use this file to discover all available pages before exploring further.

RankingService provides TriviaPP’s online leaderboard functionality by reading and writing player scores to a Firebase Firestore collection named ranking. Each document records a player name, their session score, and the calendar date of the session. When retrieving the leaderboard, the service fetches all documents ordered by score and then filters client-side to today’s date, effectively presenting a fresh daily ranking on every load. For instructions on setting up the Firebase project and providing your Firestore credentials, see the Firebase setup guide.

Constructor / Dependencies

RankingService is provided in the root injector and has no Angular constructor dependencies — it initialises Firebase and Firestore directly in the class body using the modular Firebase SDK.
@Injectable({ providedIn: 'root' })
export class RankingService {
  private app = getApps().length ? getApp() : initializeApp(firebaseConfig);
  private db  = getFirestore(this.app);
}
Lazy Firebase initialisation: The service checks getApps().length before calling initializeApp(). This guard prevents a “Firebase app already exists” error when multiple services or hot-module reloads attempt to initialise the same Firebase project.
firebaseConfig is imported from src/firebase.config.ts. Keep this file out of version control and provide the credentials via environment variables or a CI secret. See the Firebase setup guide for details.

Firestore Document Shape

Every document written to the ranking collection follows this structure:
{
  name: string;   // Player's display name
  score: number;  // Total score earned during the session
  date: string;   // ISO calendar date in YYYY-MM-DD format (e.g. "2025-07-04")
}
Documents are never updated in place — each game session produces a new document. Daily filtering is applied on read.

Methods

addScore()

Writes a new score document to the ranking Firestore collection, stamped with today’s date.
async addScore(name: string, score: number): Promise<void>
name
string
required
The player’s display name (sourced from StorageService.getProfile().displayName).
score
number
required
The total score achieved in the completed game session.
The date field is derived automatically:
const today = new Date().toISOString().split('T')[0]; // e.g. "2025-07-04"
Date filtering is performed client-side using the device clock. Ensure the device time is accurate; a misconfigured clock will place scores on the wrong date and exclude them from the daily leaderboard.

getDailyRanking()

Retrieves all documents from the ranking collection ordered by score descending, then filters them client-side to return only entries whose date matches today.
async getDailyRanking(): Promise<any[]>
Returns an array of plain objects matching the Firestore document shape, sorted by score descending. Returns an empty array [] if no scores have been recorded today. Firestore query issued:
query(
  collection(this.db, 'ranking'),
  orderBy('score', 'desc')
)
The orderBy('score', 'desc') query requires a composite index in Firestore if combined with a where clause. The current implementation avoids a Firestore where filter by doing the date comparison in memory, so no composite index is required.

Usage Example

import { RankingService } from './services/ranking.service';
import { StorageService } from './services/storage.service';

@Component({ ... })
export class LeaderboardPage implements OnInit {
  dailyRanking: any[] = [];

  constructor(
    private rankingService: RankingService,
    private storage: StorageService
  ) {}

  async ngOnInit() {
    this.dailyRanking = await this.rankingService.getDailyRanking();
  }

  // Call this after a game session ends
  async submitScore(score: number) {
    const profile = this.storage.getProfile();
    const name = profile.displayName || 'Anónimo';

    await this.rankingService.addScore(name, score);

    // Refresh the board immediately after submission
    this.dailyRanking = await this.rankingService.getDailyRanking();
  }
}
<!-- Leaderboard template -->
<ion-list>
  <ion-item *ngFor="let entry of dailyRanking; let i = index">
    <ion-label>
      <h2>{{ i + 1 }}. {{ entry.name }}</h2>
      <p>{{ entry.score }} pts</p>
    </ion-label>
  </ion-item>
</ion-list>
Combine RankingService (online) with StorageService.addRankingItem() (offline) for a resilient leaderboard experience. Submit to Firestore when online, and always write to localStorage as the local fallback.

Build docs developers (and LLMs) love