mirror of
https://github.com/bitwarden/browser
synced 2026-02-10 21:50:15 +00:00
Merge branch 'achievement-notifier-with-web-and-browser-testbed' into innovation/user-achievements/event-stream-prototype
This commit is contained in:
@@ -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>;
|
||||
}
|
||||
@@ -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,
|
||||
),
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
22
libs/common/src/tools/achievements/event-store.ts
Normal file
22
libs/common/src/tools/achievements/event-store.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./vault-item-added";
|
||||
export * from "./login-item-added";
|
||||
@@ -0,0 +1,45 @@
|
||||
import { Achievement, AchievementId } from "../../types";
|
||||
import { VaultItemCreatedProgress } from "../metrics/metrics";
|
||||
|
||||
const LoginItems_1_Added_Achievement: Achievement = {
|
||||
achievement: "login-item-added" as AchievementId,
|
||||
name: "Access granted",
|
||||
description: "Saved your first login item with Bitwarden",
|
||||
validator: "Threshold",
|
||||
active: { metric: VaultItemCreatedProgress, high: 1 },
|
||||
hidden: false,
|
||||
};
|
||||
|
||||
const LoginItems_10_Added_Achievement: Achievement = {
|
||||
achievement: "10-login-items-added" as AchievementId,
|
||||
name: "10 Login Items Added",
|
||||
description: "Add 10 item of type login to your vault",
|
||||
validator: "Threshold",
|
||||
active: { metric: VaultItemCreatedProgress, high: 10 },
|
||||
hidden: false,
|
||||
};
|
||||
|
||||
const LoginItems_50_Added_Achievement: Achievement = {
|
||||
achievement: "50-login-items-added" as AchievementId,
|
||||
name: "50 Login Items Added",
|
||||
description: "Add 50 item of type login to your vault",
|
||||
validator: "Threshold",
|
||||
active: { metric: VaultItemCreatedProgress, high: 50 },
|
||||
hidden: false,
|
||||
};
|
||||
|
||||
const LoginItems_100_Added_Achievement: Achievement = {
|
||||
achievement: "100-login-items-added" as AchievementId,
|
||||
name: "100 Login Items Added",
|
||||
description: "Add 100 item of type login to your vault",
|
||||
validator: "Threshold",
|
||||
active: { metric: VaultItemCreatedProgress, high: 100 },
|
||||
hidden: false,
|
||||
};
|
||||
|
||||
export {
|
||||
LoginItems_1_Added_Achievement,
|
||||
LoginItems_10_Added_Achievement,
|
||||
LoginItems_50_Added_Achievement,
|
||||
LoginItems_100_Added_Achievement,
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
import { Achievement, AchievementId } from "../../types";
|
||||
import { VaultItemCreatedProgress } from "../metrics/metrics";
|
||||
|
||||
const VaultItems_1_Added_Achievement: Achievement = {
|
||||
achievement: "vault-item-added" as AchievementId,
|
||||
name: "The chosen one",
|
||||
description: "Saved your fist item to Bitwarden",
|
||||
validator: "Threshold",
|
||||
active: { metric: VaultItemCreatedProgress, high: 1 },
|
||||
hidden: false,
|
||||
};
|
||||
|
||||
const VaultItems_10_Added_Achievement: Achievement = {
|
||||
achievement: "10-vault-items-added" as AchievementId,
|
||||
name: "A decade of security",
|
||||
description: "Saved your 10th item to Bitwarden",
|
||||
validator: "Threshold",
|
||||
active: { metric: VaultItemCreatedProgress, high: 10 },
|
||||
hidden: false,
|
||||
};
|
||||
|
||||
const VaultItems_50_Added_Achievement: Achievement = {
|
||||
achievement: "50-vault-items-added" as AchievementId,
|
||||
name: "It's 50/50 Vault Items Added",
|
||||
description: "Saved your 50th item to Bitwarden",
|
||||
validator: "Threshold",
|
||||
active: { metric: VaultItemCreatedProgress, high: 50 },
|
||||
hidden: false,
|
||||
};
|
||||
|
||||
const VaultItems_100_Added_Achievement: Achievement = {
|
||||
achievement: "100-vault-items-added" as AchievementId,
|
||||
name: "Century mark, Now you are thinking with ciphers",
|
||||
description: "Saved your 100th item to Bitwarden",
|
||||
validator: "Threshold",
|
||||
active: { metric: VaultItemCreatedProgress, high: 100 },
|
||||
hidden: false,
|
||||
};
|
||||
|
||||
export {
|
||||
VaultItems_1_Added_Achievement,
|
||||
VaultItems_10_Added_Achievement,
|
||||
VaultItems_50_Added_Achievement,
|
||||
VaultItems_100_Added_Achievement,
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
import { MetricId } from "../../types";
|
||||
|
||||
const VaultItemCreatedProgress = "vault-item-quantity" as MetricId;
|
||||
|
||||
export { VaultItemCreatedProgress };
|
||||
Reference in New Issue
Block a user