cozy-games/packages/leaderboard/leader-board.js

65 lines
2.7 KiB
JavaScript

import { LeaderBoardReader } from './leaderboard-read.js'
import { LeaderBoardWriter } from './leaderboard-write.js'
/**
* Generic, game- AND backend-agnostic leaderboard. Nothing here knows about
* minesweeper or Firebase: the ranked value is a plain `score`, sorted in the
* configured direction and displayed through an injected formatter, while all
* storage I/O is delegated to an injected adapter (see adapters/).
*
* This is the COMBINED facade: it simply composes the two separable surfaces —
* {@link LeaderBoardReader} (read/subscribe/render) and {@link LeaderBoardWriter}
* (submit) — for consumers that want both in one object. Consumers who need only
* one half import it directly and pull in nothing from the other:
*
* import { LeaderBoardReader } from '@cozy-games/leaderboard/leaderboard-read.js'
* import { LeaderBoardWriter } from '@cozy-games/leaderboard/leaderboard-write.js'
*
* Public API is unchanged: `render()` (read) and `submit()` (write). The reader
* and writer are also exposed as `.reader` / `.writer` for direct access. Reads
* and writes may be wired to differently-privileged backend instances by passing
* the surfaces different adapters (construct a Reader and Writer directly).
*
* An adapter implements:
* - getConfig(): Promise<Object|undefined>
* - listScores({ category, since, order, limit }): Promise<Object[]> // read
* - addScore(category, entry): Promise<void> // write
* - archive(entry): Promise<void> // optional personal history // write
*/
export class LeaderBoardService {
/**
* @param {Object} options - see {@link LeaderBoardReader} and {@link LeaderBoardWriter} for the full set
* @param {Object} options.adapter - storage backend (e.g. FirebaseAdapter, SupabaseAdapter)
* @param {'asc'|'desc'} [options.scoreOrder]
* @param {(value: number) => string} [options.formatScore]
* @param {(entry: Object) => boolean} [options.qualifies]
* @param {Object} [options.labels]
* @param {Object} [options.tooltips]
* @param {string[]} [options.emptyMessages]
* @param {string} [options.loadingText]
* @param {string} [options.errorText]
* @param {string} [options.anonymousName]
*/
constructor(options = {}) {
this.adapter = options.adapter
this.reader = new LeaderBoardReader(options)
this.writer = new LeaderBoardWriter(options)
}
/**
* Read surface — render the ranked list with a duration tab bar.
* @see LeaderBoardReader#render
*/
render(category, title, duration) {
return this.reader.render(category, title, duration)
}
/**
* Write surface — submit a completed game (archive + ranked entry).
* @see LeaderBoardWriter#submit
*/
submit(entry) {
return this.writer.submit(entry)
}
}