feat(leaderboard): opt-out support — server endpoint, client method, UI button
- Server: DELETE /api/leaderboard/opt-in sets leaderboard_opt_in=0, hiding the player without deleting their row (scores preserved for re-opt-in) - SyncProvider trait: opt_out_leaderboard() default no-op method + blanket impl - SolitaireServerClient: implements opt_out_leaderboard via DELETE request with JWT refresh - Leaderboard UI: "Opt Out" button (dark red) alongside existing "Opt In" button - Server integration test: opt-out hides, opt-in restores (round-trip verified) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -46,6 +46,11 @@ pub trait SyncProvider: Send + Sync {
|
||||
async fn opt_in_leaderboard(&self, _display_name: &str) -> Result<(), SyncError> {
|
||||
Ok(())
|
||||
}
|
||||
/// Remove the authenticated player from the leaderboard.
|
||||
/// No-op for backends that don't support leaderboards.
|
||||
async fn opt_out_leaderboard(&self) -> Result<(), SyncError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Blanket impl so `Box<dyn SyncProvider + Send + Sync>` (returned by
|
||||
@@ -76,6 +81,9 @@ impl SyncProvider for Box<dyn SyncProvider + Send + Sync> {
|
||||
async fn opt_in_leaderboard(&self, display_name: &str) -> Result<(), SyncError> {
|
||||
(**self).opt_in_leaderboard(display_name).await
|
||||
}
|
||||
async fn opt_out_leaderboard(&self) -> Result<(), SyncError> {
|
||||
(**self).opt_out_leaderboard().await
|
||||
}
|
||||
}
|
||||
|
||||
pub mod stats;
|
||||
|
||||
Reference in New Issue
Block a user