Skip to content

Commit

Permalink
Merge pull request #5620 from kiva/MP-966-fe-badge-journey-should-use…
Browse files Browse the repository at this point in the history
…-tiered-badge-icons

feat: composable for tiered badge data
  • Loading branch information
dyersituations authored Oct 28, 2024
2 parents 82b00d3 + fa64544 commit 48be875
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 80 deletions.
46 changes: 5 additions & 41 deletions src/components/MyKiva/BadgesSection.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<template>
<div class="tw-w-full tw-inline-flex tw-flex-wrap tw-justify-center tw-gap-2.5">
<div
v-for="badge in badgesArray"
:key="badge.fields.key"
v-for="(badge, index) in visibleBadges"
:key="index"
class="badge-container tw-flex tw-flex-col tw-justify-between tw-p-1.5 tw-rounded"
:class="{
'tw-bg-white': badge.hasStarted,
Expand Down Expand Up @@ -50,55 +50,19 @@
</template>

<script setup>
import { computed, toRefs } from 'vue';
import { computed } from 'vue';
import { defaultBadges } from '#src/util/achievementUtils';
defineEmits(['badge-clicked']);
const props = defineProps({
badgesData: {
badgeData: {
type: Array,
default: () => ([])
},
userAchievements: {
type: Array,
default: () => ([])
}
});
const { badgesData, userAchievements } = toRefs(props);
const badgesArray = computed(() => {
const badges = [];
if (badgesData.value.length > 0) {
defaultBadges.forEach(badgeKey => {
let badgeFound = badgesData.value.find(entry => entry.fields.key === `${badgeKey}-level-1`);
const userAchievement = userAchievements.value.find(entry => entry.id === badgeKey);
if (!userAchievement) {
badgeFound = {
...badgeFound,
hasStarted: false,
level: 0,
};
} else {
// TODO: Update this status field when we have the data from the backend
const hasStarted = userAchievement.status !== 'NO_PROGRESS';
// TODO: Change this to level when we have the data from the backend
const level = userAchievement.totalProgressToAchievement;
badgeFound = {
...badgeFound,
hasStarted,
level,
...userAchievement,
};
}
badges.push(badgeFound);
});
}
return badges;
});
const visibleBadges = computed(() => props.badgeData.filter(b => defaultBadges.includes(b.id)));
const getBadgeTitle = badge => badge?.fields?.challengeName ?? '';
Expand Down
125 changes: 125 additions & 0 deletions src/composables/useBadgeData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { onMounted, ref, computed } from 'vue';
import userAchievementProgressQuery from '#src/graphql/query/userAchievementProgress.graphql';
import contentfulEntriesQuery from '#src/graphql/query/contentfulEntries.graphql';
import logReadQueryError from '#src/util/logReadQueryError';

/**
* Utilities for loading and combining tiered badge data
*
* @param apollo The current Apollo client instance
* @returns Cleaned up tiered badge data
*/
export default function useBadgeData(apollo) {
const badgeAchievementData = ref();
const badgeContentfulData = ref();

const getContentfulLevelData = entry => ({
id: entry?.fields?.key?.replace(/-level-\d+/, '') ?? '',
level: +(entry?.fields?.key?.replace(/\D/g, '') ?? ''),
levelName: entry?.fields?.challengeName ?? '',
imageUrl: entry?.fields?.badgeImage?.fields?.file?.url ?? '',
});

const fetchAchievementData = () => {
apollo.query({ query: userAchievementProgressQuery })
.then(result => {
badgeAchievementData.value = result.data?.userAchievementProgress?.tieredLendingAchievements ?? [];
}).catch(e => {
logReadQueryError(e, 'useBadgeData userAchievementProgressQuery');
});
};

const fetchContentfulData = () => {
apollo.query({
query: contentfulEntriesQuery,
variables: {
contentType: 'challenge',
limit: 200,
}
})
.then(result => {
badgeContentfulData.value = (result.data?.contentful?.entries?.items ?? [])
.map(entry => getContentfulLevelData(entry));
}).catch(e => {
logReadQueryError(e, 'useBadgeData contentfulEntriesQuery');
});
};

/**
* {
* "contentfulData": [
* {
* "id": "",
* "level": 1,
* "levelName": "",
* "imageUrl": ""
* },
* ...
* ],
* "achievementData": {
* "id": "",
* "totalProgressToAchievement": 0,
* "tiers": [
* {
* "target": 1,
* "tierStatement": "",
* "completedDate": null,
* "learnMoreURL": "",
* "level": 1
* },
* ...
* ]
* },
* "hasStarted": false,
* "level": undefined
* }
*/
const badgeData = computed(() => {
const badges = [];

// Ensure data loaded from both achievement service and Contentful
if (badgeAchievementData.value && badgeContentfulData.value) {
// Currently only targeting specific tiered badges
badgeAchievementData.value.forEach(achievementData => {
const contentfulData = badgeContentfulData.value.filter(entry => entry.id === achievementData.id);

// Ensure badges are defined in both locations
if (achievementData && contentfulData) {
const sortedTiers = [...(achievementData.tiers ?? [])].map((t, i) => {
const tier = JSON.parse(JSON.stringify(t));
// Ensure achievement data includes numerical level of tier
tier.level = i + 1;
return tier;
});

sortedTiers.sort((a, b) => a.target - b.target);

// Get specific properties used in the UI
const completedTiers = sortedTiers.filter(t => !!t.completedDate);
const hasStarted = completedTiers.length > 0;
const level = hasStarted ? completedTiers[completedTiers.length - 1].level : undefined;

// Combine the achievement service and Contentful data
badges.push({
id: achievementData.id,
contentfulData,
achievementData: {
...achievementData,
tiers: sortedTiers,
},
hasStarted,
level,
});
}
});
}
return badges;
});

onMounted(() => {
fetchAchievementData();
fetchContentfulData();
});

return { badgeAchievementData, badgeData };
}
44 changes: 5 additions & 39 deletions src/pages/Portfolio/MyKiva/MyKivaPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,7 @@
</section>
</MyKivaContainer>
<section class="tw-my-2">
<MyKivaStats
:user-achievements="userAchievements"
/>
<MyKivaStats :user-achievements="badgeAchievementData" />
<MyKivaContainer>
<div class="tw-flex tw-flex-col tw-w-full lg:tw-hidden tw-mt-2">
<router-link
Expand Down Expand Up @@ -90,11 +88,7 @@
>
My impact journeys
</h3>
<BadgesSection
:badges-data="badgesData"
:user-achievements="userAchievements"
@badge-clicked="handleBadgeClicked"
/>
<BadgesSection :badge-data="badgeData" @badge-clicked="handleBadgeClicked" />

<BadgeModal
v-if="selectedBadgeData"
Expand All @@ -115,8 +109,6 @@ import WwwPage from '#src/components/WwwFrame/WwwPage';
import MyKivaNavigation from '#src/components/MyKiva/MyKivaNavigation';
import myKivaQuery from '#src/graphql/query/myKiva.graphql';
import updatesQuery from '#src/graphql/query/loanUpdates.graphql';
import userAchievementProgressQuery from '#src/graphql/query/userAchievementProgress.graphql';
import contentfulEntriesQuery from '#src/graphql/query/contentfulEntries.graphql';
import MyKivaHero from '#src/components/MyKiva/MyKivaHero';
import MyKivaProfile from '#src/components/MyKiva/MyKivaProfile';
import MyKivaContainer from '#src/components/MyKiva/MyKivaContainer';
Expand All @@ -125,6 +117,7 @@ import JournalUpdatesCarousel from '#src/components/MyKiva/JournalUpdatesCarouse
import BadgeModal from '#src/components/MyKiva/BadgeModal';
import BadgesSection from '#src/components/MyKiva/BadgesSection';
import MyKivaStats from '#src/components/MyKiva/MyKivaStats';
import useBadgeData from '#src/composables/useBadgeData';
import {
ref,
Expand All @@ -138,6 +131,8 @@ const MY_KIVA_EXP_KEY = 'my_kiva_page';
const apollo = inject('apollo');
const $kvTrackEvent = inject('$kvTrackEvent');
const { badgeAchievementData, badgeData } = useBadgeData(apollo);
const lender = ref(null);
const showNavigation = ref(false);
const userInfo = ref({});
Expand All @@ -146,8 +141,6 @@ const activeLoan = ref({});
const loanUpdates = ref([]);
const showBadgeModal = ref(false);
const selectedBadgeData = ref();
const userAchievements = ref([]);
const badgesData = ref([]);
const isLoading = computed(() => !lender.value);
Expand Down Expand Up @@ -179,30 +172,6 @@ const handleSelectedLoan = loan => {
fetchLoanUpdates(activeLoan.value.id);
};
const fetchUserAchievements = () => {
apollo.query({ query: userAchievementProgressQuery })
.then(result => {
userAchievements.value = result.data?.userAchievementProgress?.tieredLendingAchievements ?? [];
}).catch(e => {
logReadQueryError(e, 'MyKivaPage userAchievementProgressQuery');
});
};
const fetchBadgesData = () => {
apollo.query({
query: contentfulEntriesQuery,
variables: {
contentType: 'challenge',
limit: 200,
}
})
.then(result => {
badgesData.value = result.data?.contentful?.entries?.items ?? [];
}).catch(e => {
logReadQueryError(e, 'MyKivaPage contentfulEntriesQuery');
});
};
apollo.query({ query: myKivaQuery })
.then(result => {
userInfo.value = result.data?.my ?? {};
Expand All @@ -227,8 +196,5 @@ onMounted(() => {
);
$kvTrackEvent('portfolio', 'view', 'new-my-kiva');
fetchBadgesData();
fetchUserAchievements();
});
</script>

0 comments on commit 48be875

Please sign in to comment.