From 0809ca24fea5af824807ea8333ab9175a3cbf393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=A8=20Audrey=20=E2=9C=A8?= Date: Thu, 20 Mar 2025 20:31:22 -0400 Subject: [PATCH] wire next achievement service to achievements list --- .../achievements-list.component.html | 12 +- .../achievements-list.component.ts | 124 +++++++----------- .../achievements/next-achievement.service.ts | 2 +- 3 files changed, 55 insertions(+), 83 deletions(-) diff --git a/libs/angular/src/tools/achievements/achievements-list.component.html b/libs/angular/src/tools/achievements/achievements-list.component.html index 2e6076968d8..1111b191e0b 100644 --- a/libs/angular/src/tools/achievements/achievements-list.component.html +++ b/libs/angular/src/tools/achievements/achievements-list.component.html @@ -1,4 +1,4 @@ - +

{{ "achievements" | i18n }} @@ -7,14 +7,14 @@ - @for (achievement of allAchievementCards; track achievement.name) { + @for (achievement of achievements; track achievement.name) { } diff --git a/libs/angular/src/tools/achievements/achievements-list.component.ts b/libs/angular/src/tools/achievements/achievements-list.component.ts index 58f386651b3..06bb74979c5 100644 --- a/libs/angular/src/tools/achievements/achievements-list.component.ts +++ b/libs/angular/src/tools/achievements/achievements-list.component.ts @@ -1,20 +1,18 @@ import { CommonModule } from "@angular/common"; -import { Component, OnInit } from "@angular/core"; +import { Component } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; -import { firstValueFrom } from "rxjs"; +import { filter, switchMap } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { AchievementService } from "@bitwarden/common/tools/achievements/achievement.service.abstraction"; +import { AccountService, Account } from "@bitwarden/common/auth/abstractions/account.service"; +import { NextAchievementService } from "@bitwarden/common/tools/achievements/next-achievement.service"; import { - LoginItems_1_Added_Achievement, - LoginItems_10_Added_Achievement, - LoginItems_50_Added_Achievement, - VaultItems_10_Added_Achievement, - VaultItems_1_Added_Achievement, - VaultItems_50_Added_Achievement, -} from "@bitwarden/common/tools/achievements/examples/achievements"; -import { UserId } from "@bitwarden/common/types/guid"; + Achievement, + AchievementEarnedEvent, + AchievementId, + AchievementProgressEvent, + MetricId, +} from "@bitwarden/common/tools/achievements/types"; import { ButtonModule, Icon, @@ -26,11 +24,6 @@ import { } from "@bitwarden/components"; import { AchievementItem } from "./achievement-item.component"; -import { - OneLoginItemCreatedIcon, - TenLoginItemsCreatedIcon, - FiftyLoginItemsCreatedIcon, -} from "./icons"; import { AchievementIcon } from "./icons/achievement.icon"; import { iconMap } from "./icons/iconMap"; @@ -50,72 +43,51 @@ import { iconMap } from "./icons/iconMap"; AchievementItem, ], }) -export class AchievementsListComponent implements OnInit { - private currentUserId: UserId; - - //FIXME Should be retrieved from achievementService or possibly AchievementManager - private allAchievements = [ - VaultItems_1_Added_Achievement, - VaultItems_10_Added_Achievement, - VaultItems_50_Added_Achievement, - LoginItems_1_Added_Achievement, - ]; - - mockAchievements = [ - { - ...LoginItems_1_Added_Achievement, - earned: false, - progress: 0, - date: new Date(0), - icon: OneLoginItemCreatedIcon, - }, - { - ...LoginItems_10_Added_Achievement, - earned: false, - progress: 1, - date: new Date(0), - icon: TenLoginItemsCreatedIcon, - }, - { - ...LoginItems_50_Added_Achievement, - earned: true, - progress: 0, - date: new Date(0), - icon: FiftyLoginItemsCreatedIcon, - }, - ]; - //FIXME uses mockedData for AchievmentsList - allAchievementCards = this.mockAchievements; - // allAchievementCards = this.allAchievements.map(achievement => { return { ...achievement, earned: true, progress: 0, date: new Date(0), icon: this.lookupIcon(achievement.achievement) } }); +export class AchievementsListComponent { + protected achievements: Map; + private _earned: Map = new Map(); + private _progress: Map = new Map(); constructor( - private achievementService: AchievementService, + private achievementService: NextAchievementService, private accountService: AccountService, ) { - //FIXME AchievementProgressEvent is missing an identifier for a specific achievement - this.achievementService - .achievementsInProgress$(this.currentUserId) - .pipe(takeUntilDestroyed()) - .subscribe((event) => { - this.allAchievementCards.find((a) => a.name === event.achievement.name); - const index = this.allAchievementCards.findIndex((a) => a.name === event.achievement.name); - this.allAchievementCards[index].progress = event.achievement.value; - }); - this.achievementService - .achievementsEarned$(this.currentUserId) - .pipe(takeUntilDestroyed()) - .subscribe((event) => { - const index = this.allAchievementCards.findIndex((a) => a.name === event.achievement.name); - this.allAchievementCards[index].earned = true; - this.allAchievementCards[index].date = new Date(event["@timestamp"]); - }); + this.achievements = achievementService.achievementMap(); + + this.accountService.activeAccount$ + .pipe( + filter((account): account is Account => !!account), + switchMap((account) => this.achievementService.earnedMap$(account)), + takeUntilDestroyed(), + ) + .subscribe((earned) => (this._earned = earned)); + + this.accountService.activeAccount$ + .pipe( + filter((account): account is Account => !!account), + switchMap((account) => this.achievementService.metricsMap$(account)), + takeUntilDestroyed(), + ) + .subscribe((progress) => (this._progress = progress)); } - async ngOnInit() { - this.currentUserId = (await firstValueFrom(this.accountService.activeAccount$)).id; + protected isEarned(achievement: Achievement) { + return this._earned.has(achievement.achievement); } - lookupIcon(achievementName: string): Icon { - return (iconMap[achievementName] as Icon) ?? AchievementIcon; + protected earnedDate(achievement: Achievement) { + return new Date(this._earned.get(achievement.achievement)?.["@timestamp"] ?? 0); + } + + protected progress(achievement: Achievement) { + if (achievement.active === "until-earned") { + return -1; + } + + return this._progress.get(achievement.active.metric)?.achievement?.value ?? -1; + } + + protected lookupIcon(achievement: Achievement): Icon { + return (iconMap[achievement.achievement] as Icon) ?? AchievementIcon; } } diff --git a/libs/common/src/tools/achievements/next-achievement.service.ts b/libs/common/src/tools/achievements/next-achievement.service.ts index 461293d83ba..7782b1369a2 100644 --- a/libs/common/src/tools/achievements/next-achievement.service.ts +++ b/libs/common/src/tools/achievements/next-achievement.service.ts @@ -65,7 +65,7 @@ export class NextAchievementService implements AchievementServiceAbstraction { } earnedMap$(account: Account) { - return this.getHub(account).metrics$(); + return this.getHub(account).earned$(); } progressStream$(account: Account, all: boolean = false) {