1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-13 15:03:26 +00:00
Naive EventStore (will be replaced by AchievementHub)
AchievementService functionality overlaps with AchievementHub, besides retrieving Achievement configuration
AchievementNotifier subscribes to the AchievementService and filters on AchievementEarned and per Device
 - Needs to also be migrated to listen to the AchievementHub
This commit is contained in:
Daniel James Smith
2025-03-19 16:53:39 +01:00
parent 02dbf172f5
commit 0456ffa048
7 changed files with 190 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
import { Observable } from "rxjs";
import { UserId } from "@bitwarden/common/types/guid";
import { Achievement, AchievementEarnedEvent, AchievementProgressEvent } from "./types";
export abstract class AchievementService {
abstract achievementById$: (achievementId: string) => Observable<Achievement>;
abstract achievementsEarned$: (userId: UserId) => Observable<AchievementEarnedEvent>;
abstract achievementsInProgress$: (userId: UserId) => Observable<AchievementProgressEvent>;
}

View File

@@ -0,0 +1,60 @@
import { filter, find, from, Observable } from "rxjs";
import { UserId } from "@bitwarden/common/types/guid";
import { AchievementService as AchievementServiceAbstraction } from "./achievement.service.abstraction";
import { EventStoreAbstraction } from "./event-store.abstraction.service";
import {
VaultItems_1_Added_Achievement,
VaultItems_10_Added_Achievement,
} from "./examples/achievements";
import { isEarnedEvent, isProgressEvent } from "./meta";
import {
Achievement,
AchievementEarnedEvent,
AchievementEvent,
AchievementId,
AchievementProgressEvent,
} from "./types";
// Service might be deprecated in favor of the AchievmentHub
// The hub is currently missing a way of listing all achievements, finding by id, but that could be possibly done via the AchievementManager
export class DefaultAchievementService implements AchievementServiceAbstraction {
private _achievements: Achievement[] = [
VaultItems_1_Added_Achievement,
VaultItems_10_Added_Achievement,
];
private _achievementsSubject = from(this._achievements);
achievementById$: (achievementId: string) => Observable<Achievement>;
// Provided by the AchievementHub
achievementsEarned$: (userId: UserId) => Observable<AchievementEarnedEvent>;
// Provided by the AchievementHub
achievementsInProgress$: (userId: UserId) => Observable<AchievementProgressEvent>;
constructor(protected eventStore: EventStoreAbstraction) {
this.achievementById$ = (achievementId: AchievementId) =>
this._achievementsSubject.pipe(find((item: Achievement) => item.name === achievementId));
this.achievementsEarned$ = (userId: UserId) => {
return this.eventStore.events$.pipe(
filter(
(event): event is AchievementEarnedEvent =>
isEarnedEvent(event as AchievementEvent) && event.user.id === userId,
),
);
};
this.achievementsInProgress$ = (userId: UserId) => {
return this.eventStore.events$.pipe(
filter(
(event): event is AchievementProgressEvent =>
isProgressEvent(event as AchievementEvent) && event.user.id === userId,
),
);
};
}
}

View File

@@ -0,0 +1,10 @@
import { Observable } from "rxjs";
import { AchievementEarnedEvent, AchievementProgressEvent, UserActionEvent } from "./types";
export abstract class EventStoreAbstraction {
abstract events$: Observable<UserActionEvent | AchievementProgressEvent | AchievementEarnedEvent>;
abstract addEvent(
event: UserActionEvent | AchievementProgressEvent | AchievementEarnedEvent,
): boolean;
}

View File

@@ -0,0 +1,22 @@
import { Observable, Subject } from "rxjs";
import { EventStoreAbstraction } from "./event-store.abstraction.service";
import { AchievementEarnedEvent, AchievementProgressEvent } from "./types";
// Will be replaced by the achievementHub
export class EventStore implements EventStoreAbstraction {
private _events = new Subject<AchievementProgressEvent | AchievementEarnedEvent>();
events$: Observable<AchievementProgressEvent | AchievementEarnedEvent> =
this._events.asObservable();
constructor() {}
addEvent(event: AchievementProgressEvent | AchievementEarnedEvent): boolean {
// FIXME Collapse existing of same metric/higher count AchievementProgressEvents
//eslint-disable-next-line no-console
console.log("EventStore.addEvent", event);
this._events.next(event);
return true;
}
}