1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-10 05:30:01 +00:00

wire next achievement service to achievements list

This commit is contained in:
✨ Audrey ✨
2025-03-20 20:31:22 -04:00
parent 91e40cc54f
commit 0809ca24fe
3 changed files with 55 additions and 83 deletions

View File

@@ -1,4 +1,4 @@
<bit-section *ngIf="allAchievementCards?.length > 0">
<bit-section *ngIf="achievements.size > 0">
<bit-section-header>
<h2 class="tw-font-bold" bitTypography="h6">
{{ "achievements" | i18n }}
@@ -7,14 +7,14 @@
</bit-section-header>
<bit-item-group>
@for (achievement of allAchievementCards; track achievement.name) {
@for (achievement of achievements; track achievement.name) {
<achievement-item
[icon]="achievement.icon"
[icon]="lookupIcon(achievement)"
[title]="achievement.name"
[description]="achievement.description"
[earned]="achievement.earned"
[date]="achievement.date"
[progress]="achievement.progress"
[earned]="isEarned(achievement)"
[date]="earnedDate(achievement)"
[progress]="progress(achievement)"
></achievement-item>
}
</bit-item-group>

View File

@@ -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<AchievementId, Achievement>;
private _earned: Map<AchievementId, AchievementEarnedEvent> = new Map();
private _progress: Map<MetricId, AchievementProgressEvent> = 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;
}
}

View File

@@ -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) {