From 2c29b716dbc179ef2cf641e4aaf60dc933acad9a Mon Sep 17 00:00:00 2001 From: Christian Bedon Date: Thu, 21 Nov 2024 19:33:37 -0500 Subject: [PATCH 1/7] feat: add tiered badges to BadgesList component --- src/components/LenderProfile/LenderBadges.vue | 104 +++++------------- src/composables/useBadgeData.js | 53 ++++++++- .../query/userAchievementProgress.graphql | 4 +- .../Portfolio/LendingStats/BadgesList.vue | 85 +++++--------- .../LendingStats/LendingStatsPage.vue | 40 +++++-- .../specs/composables/useBadgeData.spec.js | 48 ++++++++ 6 files changed, 192 insertions(+), 142 deletions(-) diff --git a/src/components/LenderProfile/LenderBadges.vue b/src/components/LenderProfile/LenderBadges.vue index 7f73727961..4ecdb0b254 100644 --- a/src/components/LenderProfile/LenderBadges.vue +++ b/src/components/LenderProfile/LenderBadges.vue @@ -1,6 +1,6 @@ - diff --git a/src/composables/useBadgeData.js b/src/composables/useBadgeData.js index 7f93611da4..a44ff87640 100644 --- a/src/composables/useBadgeData.js +++ b/src/composables/useBadgeData.js @@ -51,8 +51,8 @@ export default function useBadgeData() { * * @param apollo The current instance of Apollo */ - const fetchAchievementData = apollo => { - apollo.query({ query: userAchievementProgressQuery }) + const fetchAchievementData = (apollo, publicId = null) => { + apollo.query({ query: userAchievementProgressQuery, variables: { publicId } }) .then(result => { badgeAchievementData.value = [ ...(result.data?.userAchievementProgress?.lendingAchievements ?? []), @@ -388,6 +388,53 @@ export default function useBadgeData() { return displayedBadge ?? {}; }; + /** + * Get completed badges of a user + * + * @param badges The badges to get the completed badges from + * @returns Completed badges + */ + const getCompletedBadges = badges => { + const completedBadgesArr = []; + + badges?.forEach(badge => { + if (badge.achievementData?.tiers?.length) { + const { tiers } = badge.achievementData; + tiers.forEach(tier => { + if (tier.completedDate) { + completedBadgesArr.push({ + ...badge, + earnedAtDate: tier.completedDate, + level: tier.level, + }); + } + }); + } + if (badge?.achievementData?.milestoneProgress?.length) { + const earnedAtDate = badge.achievementData?.milestoneProgress?.[0]?.earnedAtDate; + if (earnedAtDate) { + completedBadgesArr.push({ + ...badge, + earnedAtDate, + level: 0, + }); + } + } + }); + + return completedBadgesArr; + }; + + const completedBadges = computed(() => { + const completedBadgesArr = getCompletedBadges(badgeData.value); + + completedBadgesArr.sort((a, b) => { + return new Date(a.earnedAtDate) - new Date(b.earnedAtDate); + }); + + return completedBadgesArr; + }); + return { fetchAchievementData, fetchContentfulData, @@ -400,9 +447,11 @@ export default function useBadgeData() { getBadgeWithVisibleTiers, getLastCompletedBadgeLevelData, getHighestPriorityDisplayBadge, + getCompletedBadges, badgeAchievementData, badgeData, badgeLoanIdData, isBadgeKeyValid, + completedBadges, }; } diff --git a/src/graphql/query/userAchievementProgress.graphql b/src/graphql/query/userAchievementProgress.graphql index 319de66b97..7450817ca1 100644 --- a/src/graphql/query/userAchievementProgress.graphql +++ b/src/graphql/query/userAchievementProgress.graphql @@ -1,5 +1,5 @@ -query UserAchievementProgress { - userAchievementProgress { +query UserAchievementProgress($publicId: String) { + userAchievementProgress(publicId: $publicId) { id lendingAchievements { id diff --git a/src/pages/Portfolio/LendingStats/BadgesList.vue b/src/pages/Portfolio/LendingStats/BadgesList.vue index 8ae5a04a3b..812751c0c6 100644 --- a/src/pages/Portfolio/LendingStats/BadgesList.vue +++ b/src/pages/Portfolio/LendingStats/BadgesList.vue @@ -22,16 +22,21 @@

- +
- {{ challenge.challengeName }} -

- {{ challenge.dateTagline }} + + {{ getBadgeTitle(badge) }} + +

+ {{ getBadgeDate(badge) }}

@@ -39,9 +44,8 @@ diff --git a/src/composables/useBadgeData.js b/src/composables/useBadgeData.js index 3f6f4bc741..11bc34ba5f 100644 --- a/src/composables/useBadgeData.js +++ b/src/composables/useBadgeData.js @@ -344,7 +344,7 @@ export default function useBadgeData() { levelName: contentfulData.challengeName, }; } - } else if (badge.achievementData?.tiers?.length) { + } else if (badge?.achievementData?.tiers?.length) { const tiers = JSON.parse(JSON.stringify(badge.achievementData.tiers)); tiers.sort((a, b) => new Date(a.completedDate) - new Date(b.completedDate)); const levelIndex = tiers[0].level - 1; @@ -426,6 +426,11 @@ export default function useBadgeData() { return completedBadgesArr; }; + /** + * Get completed badges sorted by earned date + * + * @returns Completed badges sorted by earned date + */ const completedBadges = computed(() => { const completedBadgesArr = getCompletedBadges(badgeData.value); diff --git a/src/pages/Portfolio/LendingStats/BadgesList.vue b/src/pages/Portfolio/LendingStats/BadgesList.vue index 812751c0c6..d11ccbf87d 100644 --- a/src/pages/Portfolio/LendingStats/BadgesList.vue +++ b/src/pages/Portfolio/LendingStats/BadgesList.vue @@ -58,10 +58,6 @@ export default { type: Array, default: () => ([]) }, - totalPossibleBadges: { - type: Number, - default: 0 - }, isLoading: { type: Boolean, default: false @@ -87,7 +83,6 @@ export default { const badgeData = badge?.contentfulData?.find(data => data.level === badge.level); return badgeData?.imageUrl ?? ''; }, - getBadgeDate(badge) { const earnedAtDate = badge.earnedAtDate ? Date.parse(badge.earnedAtDate) : new Date(); return format(earnedAtDate, 'MMM yyyy'); diff --git a/src/pages/Portfolio/LendingStats/LendingStatsPage.vue b/src/pages/Portfolio/LendingStats/LendingStatsPage.vue index 6d4cf01c3a..8aee83472a 100644 --- a/src/pages/Portfolio/LendingStats/LendingStatsPage.vue +++ b/src/pages/Portfolio/LendingStats/LendingStatsPage.vue @@ -23,7 +23,7 @@



@@ -178,6 +178,11 @@ export default { return completedBadgesArr; }, + totalPossibleBadges() { + return this.badgesData.reduce((acc, badge) => { + return acc + (badge?.contentfulData?.length ?? 0); + }, 0); + } }, methods: { getBadgesData() { diff --git a/test/unit/specs/composables/useBadgeData.spec.js b/test/unit/specs/composables/useBadgeData.spec.js index 185404c50e..5bc2114cf5 100644 --- a/test/unit/specs/composables/useBadgeData.spec.js +++ b/test/unit/specs/composables/useBadgeData.spec.js @@ -549,5 +549,28 @@ describe('useBadgeData.js', () => { } ]); }); + it('should return empty array when not badges', () => { + const { getCompletedBadges } = useBadgeData(); + expect(getCompletedBadges(null)).toEqual([]); + }); + it('should return empty array when badges are not well formatted', () => { + const { getCompletedBadges } = useBadgeData(); + expect(getCompletedBadges([ + { + achievementData: { + milestoneProgress: [ + { earnedAtDate: null } + ] + }, + }, + { + achievementData: { + milestoneProgress: [ + { earnedAtDate: undefined } + ] + }, + } + ])).toEqual([]); + }); }); }); From 36e8e0f98261dc193529d2338b2a6f818e8efa03 Mon Sep 17 00:00:00 2001 From: Christian Bedon Date: Mon, 25 Nov 2024 14:23:04 -0500 Subject: [PATCH 4/7] feat: remove totalPossibleBadges from start of badges section --- src/pages/Portfolio/LendingStats/BadgesSection.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Portfolio/LendingStats/BadgesSection.vue b/src/pages/Portfolio/LendingStats/BadgesSection.vue index b04df51c3b..449143a99b 100644 --- a/src/pages/Portfolio/LendingStats/BadgesSection.vue +++ b/src/pages/Portfolio/LendingStats/BadgesSection.vue @@ -6,7 +6,7 @@ v-if="!isLoading" class="tw-text-base tw-bg-brand tw-text-white tw-py-0.5 tw-px-1 tw-self-center" > - {{ badgesObtained }}/{{ totalPossibleBadges }} + {{ badgesObtained }} Date: Mon, 25 Nov 2024 15:04:00 -0500 Subject: [PATCH 5/7] fix: missing optional chaining --- src/composables/useBadgeData.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/composables/useBadgeData.js b/src/composables/useBadgeData.js index 11bc34ba5f..245389aacc 100644 --- a/src/composables/useBadgeData.js +++ b/src/composables/useBadgeData.js @@ -399,7 +399,7 @@ export default function useBadgeData() { const completedBadgesArr = []; badges?.forEach(badge => { - if (badge.achievementData?.tiers?.length) { + if (badge?.achievementData?.tiers?.length) { const { tiers } = badge.achievementData; tiers.forEach(tier => { if (tier.completedDate) { From cbced40904352da30bdf678776e5019879440c9d Mon Sep 17 00:00:00 2001 From: Christian Bedon Date: Mon, 25 Nov 2024 15:51:40 -0500 Subject: [PATCH 6/7] fix: remove totalPossibleBadges prop --- src/pages/Portfolio/LendingStats/BadgesSection.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/Portfolio/LendingStats/BadgesSection.vue b/src/pages/Portfolio/LendingStats/BadgesSection.vue index 449143a99b..67745f107c 100644 --- a/src/pages/Portfolio/LendingStats/BadgesSection.vue +++ b/src/pages/Portfolio/LendingStats/BadgesSection.vue @@ -16,7 +16,6 @@ From e2414fbb8f4e9e33efdf486f583e47d9215b012a Mon Sep 17 00:00:00 2001 From: Christian Bedon Date: Mon, 25 Nov 2024 16:44:41 -0500 Subject: [PATCH 7/7] fix: badges loading indicator --- src/pages/Portfolio/LendingStats/BadgesSection.vue | 10 +++------- src/pages/Portfolio/LendingStats/LendingStatsPage.vue | 8 +++----- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/pages/Portfolio/LendingStats/BadgesSection.vue b/src/pages/Portfolio/LendingStats/BadgesSection.vue index 67745f107c..15256aa850 100644 --- a/src/pages/Portfolio/LendingStats/BadgesSection.vue +++ b/src/pages/Portfolio/LendingStats/BadgesSection.vue @@ -38,10 +38,9 @@ export default { type: Array, default: () => [] }, - /* total number of possible badges */ - totalPossibleBadges: { - type: Number, - default: 0 + isLoading: { + type: Boolean, + default: false }, }, components: { @@ -52,9 +51,6 @@ export default { badgesObtained() { return this.completedAchievements.length ?? 0; }, - isLoading() { - return this.totalPossibleBadges === 0; - }, }, }; diff --git a/src/pages/Portfolio/LendingStats/LendingStatsPage.vue b/src/pages/Portfolio/LendingStats/LendingStatsPage.vue index 8aee83472a..cfa6900d1a 100644 --- a/src/pages/Portfolio/LendingStats/LendingStatsPage.vue +++ b/src/pages/Portfolio/LendingStats/LendingStatsPage.vue @@ -23,7 +23,7 @@



@@ -178,10 +178,8 @@ export default { return completedBadgesArr; }, - totalPossibleBadges() { - return this.badgesData.reduce((acc, badge) => { - return acc + (badge?.contentfulData?.length ?? 0); - }, 0); + badgesLoading() { + return !this.badgesData.length; } }, methods: {